diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 485e26ecae..59aad48337 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -13,6 +13,10 @@ provide the basic information we require. --> +Please look thru your error log for the string `gyp info using node-gyp@` and if the version number is less than the [current release of node-gyp](https://github.com/nodejs/node-gyp/releases) then __please upgrade__ using the instructions at https://github.com/nodejs/node-gyp/blob/main/docs/Updating-npm-bundled-node-gyp.md and try your command again. + +Requests for help with [`node-sass` are very common](https://github.com/nodejs/node-gyp/issues?q=label%3A%22Node+Sass+--%3E+Dart+Sass%22). Please be aware that this package is deprecated, you should seek alternatives and avoid opening new issues about it here. + * **Node Version**: * **Platform**: * **Compiler**: @@ -46,4 +50,3 @@ Usage: npm - diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 10156d89af..779897573a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,7 @@ ##### Checklist @@ -10,7 +10,7 @@ Contributor guide: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md - [ ] `npm install && npm test` passes - [ ] tests are included - [ ] documentation is changed or added -- [ ] commit message follows [commit guidelines](https://github.com/nodejs/node/blob/master/doc/guides/contributing/pull-requests.md#commit-message-guidelines) +- [ ] commit message follows [commit guidelines](https://github.com/googleapis/release-please#how-should-i-write-my-commits) ##### Description of change diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000000..cef38bcc06 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,60 @@ +name: release-please + +on: + push: + branches: + - main + +jobs: + release-please: + permissions: + contents: write # to create release commit (google-github-actions/release-please-action) + pull-requests: write # to create release PR (google-github-actions/release-please-action) + + runs-on: ubuntu-latest + steps: + - uses: google-github-actions/release-please-action@v2 + id: release + with: + package-name: node-gyp + release-type: node + changelog-types: > + [{"type":"feat","section":"Features","hidden":false}, + {"type":"fix","section":"Bug Fixes","hidden":false}, + {"type":"bin","section":"Core","hidden":false}, + {"type":"gyp","section":"Core","hidden":false}, + {"type":"lib","section":"Core","hidden":false}, + {"type":"src","section":"Core","hidden":false}, + {"type":"test","section":"Tests","hidden":false}, + {"type":"build","section":"Core","hidden":false}, + {"type":"clean","section":"Core","hidden":false}, + {"type":"configure","section":"Core","hidden":false}, + {"type":"install","section":"Core","hidden":false}, + {"type":"list","section":"Core","hidden":false}, + {"type":"rebuild","section":"Core","hidden":false}, + {"type":"remove","section":"Core","hidden":false}, + {"type":"deps","section":"Core","hidden":false}, + {"type":"python","section":"Core","hidden":false}, + {"type":"lin","section":"Core","hidden":false}, + {"type":"linux","section":"Core","hidden":false}, + {"type":"mac","section":"Core","hidden":false}, + {"type":"macos","section":"Core","hidden":false}, + {"type":"win","section":"Core","hidden":false}, + {"type":"windows","section":"Core","hidden":false}, + {"type":"zos","section":"Core","hidden":false}, + {"type":"doc","section":"Doc","hidden":false}, + {"type":"docs","section":"Doc","hidden":false}, + {"type":"readme","section":"Doc","hidden":false}, + {"type":"chore","section":"Miscellaneous","hidden":false}, + {"type":"refactor","section":"Miscellaneous","hidden":false}, + {"type":"ci","section":"Miscellaneous","hidden":false}, + {"type":"meta","section":"Miscellaneous","hidden":false}] + + # Standard Conventional Commits: `feat` and `fix` + # node-gyp subdirectories: `bin`, `gyp`, `lib`, `src`, `test` + # node-gyp subcommands: `build`, `clean`, `configure`, `install`, `list`, `rebuild`, `remove` + # Core abstract category: `deps` + # Languages/platforms: `python`, `lin`, `linux`, `mac`, `macos`, `win`, `window`, `zos` + # Documentation: `doc`, `docs`, `readme` + # Standard Conventional Commits: `chore` (under "Miscellaneous") + # Miscellaneous abstract categories: `refactor`, `ci`, `meta` diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2fdf4d4c23..1cca2a81d2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,51 +1,60 @@ -# TODO: Line 47, enable pytest --doctest-modules +# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources +# TODO: Line 48, enable pytest --doctest-modules name: Tests -on: [push, pull_request] +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +permissions: + contents: read # to fetch code (actions/checkout) + jobs: + Lint_Python: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: pip install --user ruff + - run: ruff --output-format=github --select="E,F,PLC,PLE,UP,W,YTT" --ignore="E721,PLC1901,S101,UP031" --target-version=py38 . Tests: + needs: Lint_Python # Lint_Python takes ~5 seconds, so wait for it to pass before running the full matrix of tests. strategy: - fail-fast: false + fail-fast: false max-parallel: 15 matrix: - node: [10.x, 12.x, 14.x] - python: [3.6, 3.8, 3.9] + node: [16.x, 18.x, 20.x] + python: ["3.8", "3.11"] os: [macos-latest, ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - name: Use Python ${{ matrix.python }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} env: - PYTHON_VERSION: ${{ matrix.python }} + PYTHON_VERSION: ${{ matrix.python }} # Why do this? - name: Install Dependencies run: | npm install --no-progress - pip install flake8 pytest + pip install pytest - name: Set Windows environment - if: matrix.os == 'windows-latest' + if: startsWith(matrix.os, 'windows') run: | echo 'GYP_MSVS_VERSION=2015' >> $Env:GITHUB_ENV echo 'GYP_MSVS_OVERRIDE_PATH=C:\\Dummy' >> $Env:GITHUB_ENV - - name: Lint Python - if: matrix.os == 'ubuntu-latest' - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Run Python tests - run: | - python -m pytest + run: python -m pytest # - name: Run doctests with pytest # run: python -m pytest --doctest-modules + - name: Environment Information + run: npx envinfo - name: Run Node tests - run: | - npm test + run: npm test diff --git a/.github/workflows/visual-studio.yml b/.github/workflows/visual-studio.yml new file mode 100644 index 0000000000..8abe36ecc2 --- /dev/null +++ b/.github/workflows/visual-studio.yml @@ -0,0 +1,37 @@ +# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources + +name: visual-studio +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + visual-studio: + strategy: + fail-fast: false + max-parallel: 8 + matrix: + os: [windows-latest] + msvs-version: [2016, 2019, 2022] # https://github.com/actions/virtual-environments/tree/main/images/win + runs-on: ${{ matrix.os }} + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Install Dependencies + run: | + npm install --no-progress + # npm audit fix --force + - name: Set Windows environment + if: startsWith(matrix.os, 'windows') + run: | + echo 'GYP_MSVS_VERSION=${{ matrix.msvs-version }}' >> $Env:GITHUB_ENV + echo 'GYP_MSVS_OVERRIDE_PATH=C:\\Dummy' >> $Env:GITHUB_ENV + - name: Environment Information + run: npx envinfo + - name: Run Node tests + run: npm test diff --git a/.gitignore b/.gitignore index 776066e34d..e906ca7280 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.swp gyp/test node_modules test/.node-gyp diff --git a/CHANGELOG.md b/CHANGELOG.md index 733a4b5dd6..edf79f7025 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,356 @@ -v7.1.2 2020-10-17 -================= +# Changelog + +## [9.4.0](https://www.github.com/nodejs/node-gyp/compare/v9.3.1...v9.4.0) (2023-06-12) + + +### Features + +* add support for native windows arm64 build tools ([bb76021](https://www.github.com/nodejs/node-gyp/commit/bb76021d35964d2bb125bc6214286f35ae4e6cad)) +* Upgrade Python linting from flake8 to ruff ([#2815](https://www.github.com/nodejs/node-gyp/issues/2815)) ([fc0ddc6](https://www.github.com/nodejs/node-gyp/commit/fc0ddc6523c62b10e5ca1257500b3ceac01450a7)) + + +### Bug Fixes + +* extract tarball to temp directory on Windows ([#2846](https://www.github.com/nodejs/node-gyp/issues/2846)) ([aaa117c](https://www.github.com/nodejs/node-gyp/commit/aaa117c514430aa2c1e568b95df1b6ed1c1fd3b6)) +* log statement is for devDir not nodedir ([#2840](https://www.github.com/nodejs/node-gyp/issues/2840)) ([55048f8](https://www.github.com/nodejs/node-gyp/commit/55048f8be5707c295fb0876306aded75638a8b63)) + + +### Miscellaneous + +* get update-gyp.py to work with Python >= v3.5 ([#2826](https://www.github.com/nodejs/node-gyp/issues/2826)) ([337e8e6](https://www.github.com/nodejs/node-gyp/commit/337e8e68209bd2481cbb11dacce61234dc5c9419)) + + +### Doc + +* docs/README.md add advise about deprecated node-sass ([#2828](https://www.github.com/nodejs/node-gyp/issues/2828)) ([6f3c2d3](https://www.github.com/nodejs/node-gyp/commit/6f3c2d3c6c0de0dbf8c7245f34c2e0b3eea53812)) +* Update README.md ([#2822](https://www.github.com/nodejs/node-gyp/issues/2822)) ([c7927e2](https://www.github.com/nodejs/node-gyp/commit/c7927e228dfde059c93e08c26b54dd8026144583)) + + +### Tests + +* remove deprecated Node.js and Python ([#2868](https://www.github.com/nodejs/node-gyp/issues/2868)) ([a0b3d1c](https://www.github.com/nodejs/node-gyp/commit/a0b3d1c3afed71a74501476fcbc6ee3fface4d13)) + +### [9.3.1](https://www.github.com/nodejs/node-gyp/compare/v9.3.0...v9.3.1) (2022-12-16) + + +### Bug Fixes + +* increase node 12 support to ^12.13 ([#2771](https://www.github.com/nodejs/node-gyp/issues/2771)) ([888efb9](https://www.github.com/nodejs/node-gyp/commit/888efb9055857afee6a6b54550722cf9ae3ee323)) + + +### Miscellaneous + +* update python test matrix ([#2774](https://www.github.com/nodejs/node-gyp/issues/2774)) ([38f01fa](https://www.github.com/nodejs/node-gyp/commit/38f01fa57d10fdb3db7697121d957bc2e0e96508)) + +## [9.3.0](https://www.github.com/nodejs/node-gyp/compare/v9.2.0...v9.3.0) (2022-10-10) + + +### Features + +* **gyp:** update gyp to v0.14.0 ([#2749](https://www.github.com/nodejs/node-gyp/issues/2749)) ([713b8dc](https://www.github.com/nodejs/node-gyp/commit/713b8dcdbf44532ca9453a127da266386cc737f8)) +* remove support for VS2015 in Node.js >=19 ([#2746](https://www.github.com/nodejs/node-gyp/issues/2746)) ([131d1a4](https://www.github.com/nodejs/node-gyp/commit/131d1a463baf034a04154bcda753a8295f112a34)) +* support IBM Open XL C/C++ on z/OS ([#2743](https://www.github.com/nodejs/node-gyp/issues/2743)) ([7d0c83d](https://www.github.com/nodejs/node-gyp/commit/7d0c83d2a95aca743dff972826d0da26203acfc4)) + +## [9.2.0](https://www.github.com/nodejs/node-gyp/compare/v9.1.0...v9.2.0) (2022-10-02) + + +### Features + +* Add proper support for IBM i ([a26494f](https://www.github.com/nodejs/node-gyp/commit/a26494fbb8883d9ef784503979e115dec3e2791e)) +* **gyp:** update gyp to v0.13.0 ([3e2a532](https://www.github.com/nodejs/node-gyp/commit/3e2a5324f1c24f3a04bca04cf54fe23d5c4d5e50)) + + +### Bug Fixes + +* node.js debugger adds stderr (but exit code is 0) -> shouldn't throw ([#2719](https://www.github.com/nodejs/node-gyp/issues/2719)) ([c379a74](https://www.github.com/nodejs/node-gyp/commit/c379a744c65c7ab07c2c3193d9c7e8f25ae1b05e)) + + +### Core + +* enable support for zoslib on z/OS ([#2600](https://www.github.com/nodejs/node-gyp/issues/2600)) ([83c0a12](https://www.github.com/nodejs/node-gyp/commit/83c0a12bf23b4cbf3125d41f9e2d4201db76c9ae)) + + +### Miscellaneous + +* update dependency - nopt@6.0.0 ([#2707](https://www.github.com/nodejs/node-gyp/issues/2707)) ([8958ecf](https://www.github.com/nodejs/node-gyp/commit/8958ecf2bb719227bbcbf155891c3186ee219a2e)) + +## [9.1.0](https://www.github.com/nodejs/node-gyp/compare/v9.0.0...v9.1.0) (2022-07-13) + + +### Features + +* Update function getSDK() to support Windows 11 SDK ([#2565](https://www.github.com/nodejs/node-gyp/issues/2565)) ([ea8520e](https://www.github.com/nodejs/node-gyp/commit/ea8520e3855374bd15b6d001fe112d58a8d7d737)) + + +### Bug Fixes + +* extend tap timeout length to allow for slow CI ([6f74c76](https://www.github.com/nodejs/node-gyp/commit/6f74c762fe3c19bdd20245cb5c02e2dfa65d9451)) +* new ca & server certs, bundle in .js file and unpack for testing ([147e3d3](https://www.github.com/nodejs/node-gyp/commit/147e3d34f44a97deb7aa507207680cf0f4e662a2)) +* re-label ([#2689](https://www.github.com/nodejs/node-gyp/issues/2689)) ([f0b7863](https://www.github.com/nodejs/node-gyp/commit/f0b7863dadfa365afc173025ae95351aec79abd9)) +* typo on readme ([bf81cd4](https://www.github.com/nodejs/node-gyp/commit/bf81cd452b931dd4dfa82762c23dd530a075d992)) + + +### Doc + +* update docs/README.md with latest version number ([62d2815](https://www.github.com/nodejs/node-gyp/commit/62d28151bf8266a34e1bcceeb25b4e6e2ae5ca5d)) + + +### Core + +* update due to rename of primary branch ([ca1f068](https://www.github.com/nodejs/node-gyp/commit/ca1f0681a5567ca8cd51acebccd37a633f19bc6a)) +* Add Python symlink to path (for non-Windows OSes only) ([#2362](https://github.com/nodejs/node-gyp/pull/2362)) ([b9ddcd5](https://github.com/nodejs/node-gyp/commit/b9ddcd5bbd93b05b03674836b6ebdae2c2e74c8c)) + + +### Tests + +* Try msvs-version: [2016, 2019, 2022] ([#2700](https://www.github.com/nodejs/node-gyp/issues/2700)) ([68b5b5b](https://www.github.com/nodejs/node-gyp/commit/68b5b5be9c94ac20c55e88654ff6f55234d7130a)) +* Upgrade GitHub Actions ([#2623](https://www.github.com/nodejs/node-gyp/issues/2623)) ([245cd5b](https://www.github.com/nodejs/node-gyp/commit/245cd5bbe4441d4f05e88f2fa20a86425419b6af)) +* Upgrade GitHub Actions ([#2701](https://www.github.com/nodejs/node-gyp/issues/2701)) ([1c64ca7](https://www.github.com/nodejs/node-gyp/commit/1c64ca7f4702c6eb43ecd16fbd67b5d939041621)) + +## [9.0.0](https://www.github.com/nodejs/node-gyp/compare/v8.4.1...v9.0.0) (2022-02-24) + + +### ⚠ BREAKING CHANGES + +* increase "engines" to "node" : "^12.22 || ^14.13 || >=16" (#2601) + +### Bug Fixes + +* _ in npm_config_ env variables ([eef4eef](https://www.github.com/nodejs/node-gyp/commit/eef4eefccb13ff6a32db862709ee5b2d4edf7e95)) +* update make-fetch-happen to a minimum of 10.0.3 ([839e414](https://www.github.com/nodejs/node-gyp/commit/839e414b63790c815a4a370d0feee8f24a94d40f)) + + +### Miscellaneous + +* add minimal SECURITY.md ([#2560](https://www.github.com/nodejs/node-gyp/issues/2560)) ([c2a1850](https://www.github.com/nodejs/node-gyp/commit/c2a185056e2e589b520fbc0bcc59c2935cd07ede)) + + +### Doc + +* Add notes/disclaimers for upgrading the copy of node-gyp that npm uses ([#2585](https://www.github.com/nodejs/node-gyp/issues/2585)) ([faf6d48](https://www.github.com/nodejs/node-gyp/commit/faf6d48f8a77c08a313baf9332358c4b1231c73c)) +* Rename and update Common-issues.md --> docs/README.md ([#2567](https://www.github.com/nodejs/node-gyp/issues/2567)) ([2ef5fb8](https://www.github.com/nodejs/node-gyp/commit/2ef5fb86277c4d81baffc0b9f642a8d86be1bfa5)) +* rephrase explanation of which node-gyp is used by npm ([#2587](https://www.github.com/nodejs/node-gyp/issues/2587)) ([a2f2988](https://www.github.com/nodejs/node-gyp/commit/a2f298870692022302fa27a1d42363c4a72df407)) +* title match content ([#2574](https://www.github.com/nodejs/node-gyp/issues/2574)) ([6e8f93b](https://www.github.com/nodejs/node-gyp/commit/6e8f93be0443f2649d4effa7bc773a9da06a33b4)) +* Update Python versions ([#2571](https://www.github.com/nodejs/node-gyp/issues/2571)) ([e069f13](https://www.github.com/nodejs/node-gyp/commit/e069f13658a8bfb5fd60f74708cf8be0856d92e3)) + + +### Core + +* add lib.target as path for searching libnode on z/OS ([1d499dd](https://www.github.com/nodejs/node-gyp/commit/1d499dd5606f39de2d34fa822fd0fa5ce17fbd06)) +* increase "engines" to "node" : "^12.22 || ^14.13 || >=16" ([#2601](https://www.github.com/nodejs/node-gyp/issues/2601)) ([6562f92](https://www.github.com/nodejs/node-gyp/commit/6562f92a6f2e67aeae081ddf5272ff117f1fab07)) +* make-fetch-happen@10.0.1 ([78f6660](https://www.github.com/nodejs/node-gyp/commit/78f66604e0df480d4f36a8fa4f3618c046a6fbdc)) + +### [8.4.1](https://www.github.com/nodejs/node-gyp/compare/v8.4.0...v8.4.1) (2021-11-19) + + +### Bug Fixes + +* windows command missing space ([#2553](https://www.github.com/nodejs/node-gyp/issues/2553)) ([cc37b88](https://www.github.com/nodejs/node-gyp/commit/cc37b880690706d3c5d04d5a68c76c392a0a23ed)) + + +### Doc + +* fix typo in powershell node-gyp update ([787cf7f](https://www.github.com/nodejs/node-gyp/commit/787cf7f8e5ddd5039e02b64ace6b7b15e06fe0a4)) + + +### Core + +* npmlog@6.0.0 ([8083f6b](https://www.github.com/nodejs/node-gyp/commit/8083f6b855bd7f3326af04c5f5269fc28d7f2508)) + +## [8.4.0](https://www.github.com/nodejs/node-gyp/compare/v8.3.0...v8.4.0) (2021-11-05) + + +### Features + +* build with config.gypi from node headers ([a27dc08](https://www.github.com/nodejs/node-gyp/commit/a27dc08696911c6d81e76cc228697243069103c1)) +* support vs2022 ([#2533](https://www.github.com/nodejs/node-gyp/issues/2533)) ([5a00387](https://www.github.com/nodejs/node-gyp/commit/5a00387e5f8018264a1822f6c4d5dbf425f21cf6)) + +## [8.3.0](https://www.github.com/nodejs/node-gyp/compare/v8.2.0...v8.3.0) (2021-10-11) + + +### Features + +* **gyp:** update gyp to v0.10.0 ([#2521](https://www.github.com/nodejs/node-gyp/issues/2521)) ([5585792](https://www.github.com/nodejs/node-gyp/commit/5585792922a97f0629f143c560efd74470eae87f)) + + +### Tests + +* Python 3.10 was release on Oct. 4th ([#2504](https://www.github.com/nodejs/node-gyp/issues/2504)) ([0a67dcd](https://www.github.com/nodejs/node-gyp/commit/0a67dcd1307f3560495219253241eafcbf4e2a69)) + + +### Miscellaneous + +* **deps:** bump make-fetch-happen from 8.0.14 to 9.1.0 ([b05b4fe](https://www.github.com/nodejs/node-gyp/commit/b05b4fe9891f718f40edf547e9b50e982826d48a)) +* refactor the creation of config.gypi file ([f2ad87f](https://www.github.com/nodejs/node-gyp/commit/f2ad87ff65f98ad66daa7225ad59d99b759a2b07)) + +## [8.2.0](https://www.github.com/nodejs/node-gyp/compare/v8.1.0...v8.2.0) (2021-08-23) + + +### Features + +* **gyp:** update gyp to v0.9.6 ([#2481](https://www.github.com/nodejs/node-gyp/issues/2481)) ([ed9a9ed](https://www.github.com/nodejs/node-gyp/commit/ed9a9ed653a17c84afa3c327161992d0da7d0cea)) + + +### Bug Fixes + +* add error arg back into catch block for older Node.js users ([5cde818](https://www.github.com/nodejs/node-gyp/commit/5cde818aac715477e9e9747966bb6b4c4ed070a8)) +* change default gyp update message ([#2420](https://www.github.com/nodejs/node-gyp/issues/2420)) ([cfd12ff](https://www.github.com/nodejs/node-gyp/commit/cfd12ff3bb0eb4525173413ef6a94b3cd8398cad)) +* doc how to update node-gyp independently from npm ([c8c0af7](https://www.github.com/nodejs/node-gyp/commit/c8c0af72e78141a02b5da4cd4d704838333a90bd)) +* missing spaces ([f0882b1](https://www.github.com/nodejs/node-gyp/commit/f0882b1264b2fa701adbc81a3be0b3cba80e333d)) + + +### Core + +* deep-copy process.config during configure ([#2368](https://www.github.com/nodejs/node-gyp/issues/2368)) ([5f1a06c](https://www.github.com/nodejs/node-gyp/commit/5f1a06c50f3b0c3d292f64948f85a004cfcc5c87)) + + +### Miscellaneous + +* **deps:** bump tar from 6.1.0 to 6.1.2 ([#2474](https://www.github.com/nodejs/node-gyp/issues/2474)) ([ec15a3e](https://www.github.com/nodejs/node-gyp/commit/ec15a3e5012004172713c11eebcc9d852d32d380)) +* fix typos discovered by codespell ([#2442](https://www.github.com/nodejs/node-gyp/issues/2442)) ([2d0ce55](https://www.github.com/nodejs/node-gyp/commit/2d0ce5595e232a3fc7c562cdf39efb77e2312cc1)) +* GitHub Actions Test on node: [12.x, 14.x, 16.x] ([#2439](https://www.github.com/nodejs/node-gyp/issues/2439)) ([b7bccdb](https://www.github.com/nodejs/node-gyp/commit/b7bccdb527d93b0bb0ce99713f083ce2985fe85c)) + + +### Doc + +* correct link to "binding.gyp files out in the wild" ([#2483](https://www.github.com/nodejs/node-gyp/issues/2483)) ([660dd7b](https://www.github.com/nodejs/node-gyp/commit/660dd7b2a822c184be8027b300e68be67b366772)) +* **wiki:** Add a link to the node-midi binding.gyp file. ([b354711](https://www.github.com/nodejs/node-gyp/commit/b3547115f6e356358138310e857c7f1ec627a8a7)) +* **wiki:** add bcrypt ([e199cfa](https://www.github.com/nodejs/node-gyp/commit/e199cfa8fc6161492d2a6ade2190510d0ebf7c0f)) +* **wiki:** Add helpful information ([4eda827](https://www.github.com/nodejs/node-gyp/commit/4eda8275c03dae6d2f5c40f3c1dbe930d84b0f2b)) +* **wiki:** Add node-canvas ([13a9553](https://www.github.com/nodejs/node-gyp/commit/13a955317b39caf98fd1f412d8d3f41599e979fd)) +* **wiki:** Add node-openvg-canvas and node-openvg. ([61f709e](https://www.github.com/nodejs/node-gyp/commit/61f709ec4d9f256a6467e9ff84430a48eeb629d1)) +* **wiki:** add one more example ([77f3632](https://www.github.com/nodejs/node-gyp/commit/77f363272930d3d4d24fd3973be22e6237128fcc)) +* **wiki:** add topcube, node-osmium, and node-osrm ([1a75d2b](https://www.github.com/nodejs/node-gyp/commit/1a75d2bf2f562ba50846893a516e111cfbb50885)) +* **wiki:** Added details for properly fixing ([3d4d9d5](https://www.github.com/nodejs/node-gyp/commit/3d4d9d52d6b5b49de06bb0bb5b68e2686d2b7ebd)) +* **wiki:** Added Ghostscript4JS ([bf4bed1](https://www.github.com/nodejs/node-gyp/commit/bf4bed1b96a7d22fba6f97f4552ad09f32ac3737)) +* **wiki:** added levelup ([1575bce](https://www.github.com/nodejs/node-gyp/commit/1575bce3a53db628bfb023fd6f3258fdf98c3195)) +* **wiki:** Added nk-mysql (nodamysql) ([5b4f2d0](https://www.github.com/nodejs/node-gyp/commit/5b4f2d0e1d5d3eadfd03aaf9c1668340f76c4bea)) +* **wiki:** Added nk-xrm-installer .gyp references, including .py scripts for providing complete reference to examples of fetching source via http, extracting, and moving files (as opposed to copying) ([ceb3088](https://www.github.com/nodejs/node-gyp/commit/ceb30885b74f6789374ef52267b84767be93ebe4)) +* **wiki:** Added tip about resolving frustrating LNK1181 error ([e64798d](https://www.github.com/nodejs/node-gyp/commit/e64798de8cac6031ad598a86d7599e81b4d20b17)) +* **wiki:** ADDED: Node.js binding to OpenCV ([e2dc777](https://www.github.com/nodejs/node-gyp/commit/e2dc77730b09d7ee8682d7713a7603a2d7aacabd)) +* **wiki:** Adding link to node-cryptopp's gyp file ([875adbe](https://www.github.com/nodejs/node-gyp/commit/875adbe2a4669fa5f2be0250ffbf98fb55e800fd)) +* **wiki:** Adding the sharp library to the list ([9dce0e4](https://www.github.com/nodejs/node-gyp/commit/9dce0e41650c3fa973e6135a79632d022c662a1d)) +* **wiki:** Adds node-fann ([23e3d48](https://www.github.com/nodejs/node-gyp/commit/23e3d485ed894ba7c631e9c062f5e366b50c416c)) +* **wiki:** Adds node-inotify and v8-profiler ([b6e542f](https://www.github.com/nodejs/node-gyp/commit/b6e542f644dbbfe22b88524ec500696e06ee4af7)) +* **wiki:** Bumping Python version from 2.3 to 2.7 as per the node-gyp readme ([55ebd6e](https://www.github.com/nodejs/node-gyp/commit/55ebd6ebacde975bf84f7bf4d8c66e64cc7cd0da)) +* **wiki:** C++ build tools version upgraded ([5b899b7](https://www.github.com/nodejs/node-gyp/commit/5b899b70db729c392ced7c98e8e17590c6499fc3)) +* **wiki:** change bcrypt url to binding.gyp file ([e11bdd8](https://www.github.com/nodejs/node-gyp/commit/e11bdd84de6144492d3eb327d67cbf2d62da1a76)) +* **wiki:** Clarification + direct link to VS2010 ([531c724](https://www.github.com/nodejs/node-gyp/commit/531c724561d947b5d870de8d52dd8c3c51c5ec2d)) +* **wiki:** Correcting the link to node-osmium ([fae7516](https://www.github.com/nodejs/node-gyp/commit/fae7516a1d2829b6e234eaded74fb112ebd79a05)) +* **wiki:** Created "binding.gyp" files out in the wild (markdown) ([d4fd143](https://www.github.com/nodejs/node-gyp/commit/d4fd14355bbe57f229f082f47bb2b3670868203f)) +* **wiki:** Created Common issues (markdown) ([a38299e](https://www.github.com/nodejs/node-gyp/commit/a38299ea340ceb0e732c6dc6a1b4760257644839)) +* **wiki:** Created Error: "pre" versions of node cannot be installed (markdown) ([98bc80d](https://www.github.com/nodejs/node-gyp/commit/98bc80d7a62ba70c881f3c39d94f804322e57852)) +* **wiki:** Created Linking to OpenSSL (markdown) ([c46d00d](https://www.github.com/nodejs/node-gyp/commit/c46d00d83bac5173dea8bbbb175a1a7de74fdaca)) +* **wiki:** Created Updating npm's bundled node gyp (markdown) ([e0ac8d1](https://www.github.com/nodejs/node-gyp/commit/e0ac8d15af46aadd1c220599e63199b154a514e6)) +* **wiki:** Created use of undeclared identifier 'TypedArray' (markdown) ([65ba711](https://www.github.com/nodejs/node-gyp/commit/65ba71139e9b7f64ac823e575ee9dbf17d937ce4)) +* **wiki:** Created Visual Studio 2010 Setup (markdown) ([5b80e83](https://www.github.com/nodejs/node-gyp/commit/5b80e834c8f79dda9fb2770a876ff3cf649c06f3)) +* **wiki:** Created Visual studio 2012 setup (markdown) ([becef31](https://www.github.com/nodejs/node-gyp/commit/becef316b6c46a33e783667720ee074a0141d1a5)) +* **wiki:** Destroyed Visual Studio 2010 Setup (markdown) ([93423b4](https://www.github.com/nodejs/node-gyp/commit/93423b43606de9664aeb79635825f5e9941ec9bc)) +* **wiki:** Destroyed Visual studio 2012 setup (markdown) ([3601508](https://www.github.com/nodejs/node-gyp/commit/3601508bb10fa05da0ddc7e70d57e4b4dd679657)) +* **wiki:** Different commands for Windows npm v6 vs. v7 ([0fce46b](https://www.github.com/nodejs/node-gyp/commit/0fce46b53340c85e8091cde347d5ed23a443c82f)) +* **wiki:** Drop in favor of ([9285ff6](https://www.github.com/nodejs/node-gyp/commit/9285ff6e451c52c070a05f05f0a9602621d91d53)) +* **wiki:** Explicit link to Visual C++ 2010 Express ([378c363](https://www.github.com/nodejs/node-gyp/commit/378c3632f02c096ed819ec8f2611c65bef0c0554)) +* **wiki:** fix link to gyp file used to build libsqlite3 ([54db8d7](https://www.github.com/nodejs/node-gyp/commit/54db8d7ac33e3f98220960b5d86cfa18a75b53cb)) +* **wiki:** Fix link to node-zipfile ([92e49a8](https://www.github.com/nodejs/node-gyp/commit/92e49a858ed69cb4847a26a5676ab56ef5e2de33)) +* **wiki:** fixed node-serialport link ([954ee53](https://www.github.com/nodejs/node-gyp/commit/954ee530b3972d1db591fce32368e4e31b5a25d8)) +* **wiki:** I highly missing it in common issue as every windows biggner face that issue ([d617fae](https://www.github.com/nodejs/node-gyp/commit/d617faee29c40871ca5c8f93efd0ce929a40d541)) +* **wiki:** if ouns that the -h did not help. I founs on github that there was support for visual studio 2015, while i couldn't install node-red beacuse it kept telling me the key 2015 was missing. looking in he gyp python code i found the local file was bot up t dat with the github repo. updating took several efforts before i tried to drop the -g option. ([408b72f](https://www.github.com/nodejs/node-gyp/commit/408b72f561329408daeb17834436e381406efcc8)) +* **wiki:** If permissions error, please try and then the command. ([ee8e1c1](https://www.github.com/nodejs/node-gyp/commit/ee8e1c1e5334096d58e0d6bca6c006f2ee9c88cb)) +* **wiki:** Improve Unix instructions ([c3e5487](https://www.github.com/nodejs/node-gyp/commit/c3e548736645b535ea5bce613d74ca3e98598243)) +* **wiki:** link to docs/ from README ([b52e487](https://www.github.com/nodejs/node-gyp/commit/b52e487eac1eb421573d1e67114a242eeff45a00)) +* **wiki:** Lower case L ([3aa2c6b](https://www.github.com/nodejs/node-gyp/commit/3aa2c6bdb07971b87505e32e32548d75264bd19f)) +* **wiki:** Make changes discussed in https://github.com/nodejs/node-gyp/issues/2416 ([1dcad87](https://www.github.com/nodejs/node-gyp/commit/1dcad873539027511a5f0243baf770ea90f6f4e2)) +* **wiki:** move wiki docs into doc/ ([f0a4835](https://www.github.com/nodejs/node-gyp/commit/f0a48355d86534ec3bdabcdb3ce3340fa2e17f39)) +* **wiki:** node-sass in the wild ([d310a73](https://www.github.com/nodejs/node-gyp/commit/d310a73d64d0065050377baac7047472f7424a1b)) +* **wiki:** node-srs was a 404 ([bbca21a](https://www.github.com/nodejs/node-gyp/commit/bbca21a1e1ede4c473aff365ca71989a5bda7b57)) +* **wiki:** Note: VS2010 seems to be no longer available! VS2013 or nothing! ([7b5dcaf](https://www.github.com/nodejs/node-gyp/commit/7b5dcafafccdceae4b8f2b53ac9081a694b6ade8)) +* **wiki:** safer doc names, remove unnecessary TypedArray doc ([161c235](https://www.github.com/nodejs/node-gyp/commit/161c2353ef5b562f4acfb2fd77608fcbd0800fc0)) +* **wiki:** sorry, forgot to mention a specific windows version. ([d69dffc](https://www.github.com/nodejs/node-gyp/commit/d69dffc16c2b1e3c60dcb5d1c35a49270ba22a35)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([7444b47](https://www.github.com/nodejs/node-gyp/commit/7444b47a7caac1e14d1da474a7fcfcf88d328017)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([d766b74](https://www.github.com/nodejs/node-gyp/commit/d766b7427851e6c2edc02e2504a7be9be7e330c0)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([d319b0e](https://www.github.com/nodejs/node-gyp/commit/d319b0e98c7085de8e51bc5595eba4264b99a7d5)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([3c6692d](https://www.github.com/nodejs/node-gyp/commit/3c6692d538f0ce973869aa237118b7d2483feccd)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([93392d5](https://www.github.com/nodejs/node-gyp/commit/93392d559ce6f250b9c7fe8177e6c88603809dc1)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([8841158](https://www.github.com/nodejs/node-gyp/commit/88411588f300e9b7c00fe516ecd977a1feeeb15c)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([81bfa1f](https://www.github.com/nodejs/node-gyp/commit/81bfa1f1b63d522a9f8a9ae9ca0c7ae90fe75140)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([d1cd237](https://www.github.com/nodejs/node-gyp/commit/d1cd237bad06fa507adb354b9e2181a14dc63d24)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([3de9e17](https://www.github.com/nodejs/node-gyp/commit/3de9e17e0b8a387eafe7bd18d0ec1e3191d118e8)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([a9b7096](https://www.github.com/nodejs/node-gyp/commit/a9b70968fb956eab3b95672048b94350e1565ca3)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([3236069](https://www.github.com/nodejs/node-gyp/commit/3236069689e7e0eb15b324fce74ab58158956f98)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([1462755](https://www.github.com/nodejs/node-gyp/commit/14627556966e5d513bdb8e5208f0e1300f68991f)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([7ab1337](https://www.github.com/nodejs/node-gyp/commit/7ab133752a6c402bb96dcd3d671d73e03e9487ad)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([640895d](https://www.github.com/nodejs/node-gyp/commit/640895d36b7448c646a3b850c1e159106f83c724)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([ced8c96](https://www.github.com/nodejs/node-gyp/commit/ced8c968457f285ab8989c291d28173d7730833c)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([27b883a](https://www.github.com/nodejs/node-gyp/commit/27b883a350ad0db6b9130d7b996f35855ec34c7a)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([d29fb13](https://www.github.com/nodejs/node-gyp/commit/d29fb134f1c4b9dd729ba95f2979e69e0934809f)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([2765891](https://www.github.com/nodejs/node-gyp/commit/27658913e6220cf0371b4b73e25a0e4ab11108a1)) +* **wiki:** Updated "binding.gyp" files out in the wild (markdown) ([dc97766](https://www.github.com/nodejs/node-gyp/commit/dc9776648d432bca6775c176641f16da14522d4c)) +* **wiki:** Updated Error: "pre" versions of node cannot be installed (markdown) ([e9f8b33](https://www.github.com/nodejs/node-gyp/commit/e9f8b33d1f87d04f22cb09a814d7c55d0fa38446)) +* **wiki:** Updated Home (markdown) ([3407109](https://www.github.com/nodejs/node-gyp/commit/3407109325cf7ba1e925656b9eb75feffab0557c)) +* **wiki:** Updated Home (markdown) ([6e392bc](https://www.github.com/nodejs/node-gyp/commit/6e392bcdd3dd1691773e6e16e1dffc35931b81e0)) +* **wiki:** Updated Home (markdown) ([65efe32](https://www.github.com/nodejs/node-gyp/commit/65efe32ccb8d446ce569453364f922dd9d27c945)) +* **wiki:** Updated Home (markdown) ([ea28f09](https://www.github.com/nodejs/node-gyp/commit/ea28f0947af91fa638be355143f5df89d2e431c8)) +* **wiki:** Updated Home (markdown) ([0e37ff4](https://www.github.com/nodejs/node-gyp/commit/0e37ff48b306c12149661b375895741d3d710da7)) +* **wiki:** Updated Home (markdown) ([b398ef4](https://www.github.com/nodejs/node-gyp/commit/b398ef46f660d2b1506508550dadfb4c35639e4b)) +* **wiki:** Updated Linking to OpenSSL (markdown) ([8919028](https://www.github.com/nodejs/node-gyp/commit/8919028921fd304f08044098434f0dc6071fb7cf)) +* **wiki:** Updated Linking to OpenSSL (markdown) ([c00eb77](https://www.github.com/nodejs/node-gyp/commit/c00eb778fc7dc27e4dab3a9219035ea20458b33b)) +* **wiki:** Updated node-levelup to node-leveldown (broken links) ([59668bb](https://www.github.com/nodejs/node-gyp/commit/59668bb0b904feccf3c09afa2fd37378c77af967)) +* **wiki:** Updated Updating npm's bundled node gyp (markdown) ([d314854](https://www.github.com/nodejs/node-gyp/commit/d31485415ef69d46effa6090c95698341965de1b)) +* **wiki:** Updated Updating npm's bundled node gyp (markdown) ([11858b0](https://www.github.com/nodejs/node-gyp/commit/11858b0655d1eee00c62ad628e719d4378803d14)) +* **wiki:** Updated Updating npm's bundled node gyp (markdown) ([33561e9](https://www.github.com/nodejs/node-gyp/commit/33561e9cbf5f4eb46111318503c77df2c6eb484a)) +* **wiki:** Updated Updating npm's bundled node gyp (markdown) ([4a7f2d0](https://www.github.com/nodejs/node-gyp/commit/4a7f2d0d869a65c99a78504976567017edadf657)) +* **wiki:** Updated Updating npm's bundled node gyp (markdown) ([979a706](https://www.github.com/nodejs/node-gyp/commit/979a7063b950c088a7f4896fc3a48e1d00dfd231)) +* **wiki:** Updated Updating npm's bundled node gyp (markdown) ([e50e04d](https://www.github.com/nodejs/node-gyp/commit/e50e04d7b6a3754ea0aa11fe8cef491b3bc5bdd4)) + +## [8.1.0](https://www.github.com/nodejs/node-gyp/compare/v8.0.0...v8.1.0) (2021-05-28) + + +### Features + +* **gyp:** update gyp to v0.9.1 ([#2402](https://www.github.com/nodejs/node-gyp/issues/2402)) ([814b1b0](https://www.github.com/nodejs/node-gyp/commit/814b1b0eda102afb9fc87e81638a9cf5b650bb10)) + + +### Miscellaneous + +* add `release-please-action` for automated releases ([#2395](https://www.github.com/nodejs/node-gyp/issues/2395)) ([07e9d7c](https://www.github.com/nodejs/node-gyp/commit/07e9d7c7ee80ba119ea760c635f72fd8e7efe198)) + + +### Core + +* fail gracefully if we can't find the username ([#2375](https://www.github.com/nodejs/node-gyp/issues/2375)) ([fca4795](https://www.github.com/nodejs/node-gyp/commit/fca4795512c67dc8420aaa0d913b5b89a4b147f3)) +* log as yes/no whether build dir was created ([#2370](https://www.github.com/nodejs/node-gyp/issues/2370)) ([245dee5](https://www.github.com/nodejs/node-gyp/commit/245dee5b62581309946872ae253226ea3a42c0e3)) + + +### Doc + +* fix v8.0.0 release date ([4b83c3d](https://www.github.com/nodejs/node-gyp/commit/4b83c3de7300457919d53f26d96ea9ad6f6bedd8)) +* remove redundant version info ([#2403](https://www.github.com/nodejs/node-gyp/issues/2403)) ([1423670](https://www.github.com/nodejs/node-gyp/commit/14236709de64b100a424396b91a5115639daa0ef)) +* Update README.md Visual Studio Community page polski to auto ([#2371](https://www.github.com/nodejs/node-gyp/issues/2371)) ([1b4697a](https://www.github.com/nodejs/node-gyp/commit/1b4697abf69ef574a48faf832a7098f4c6c224a5)) + +## v8.0.0 2021-04-03 + +* [[`0d8a6f1b19`](https://github.com/nodejs/node-gyp/commit/0d8a6f1b19)] - **ci**: update actions/setup-node to v2 (#2302) (Sora Morimoto) [#2302](https://github.com/nodejs/node-gyp/pull/2302) +* [[`15a5c7d45b`](https://github.com/nodejs/node-gyp/commit/15a5c7d45b)] - **ci**: migrate deprecated grammar (#2285) (Jiawen Geng) [#2285](https://github.com/nodejs/node-gyp/pull/2285) +* [[`06ddde27f9`](https://github.com/nodejs/node-gyp/commit/06ddde27f9)] - **deps**: sync mutual dependencies with npm (DeeDeeG) [#2348](https://github.com/nodejs/node-gyp/pull/2348) +* [[`a5fd1f41e3`](https://github.com/nodejs/node-gyp/commit/a5fd1f41e3)] - **doc**: add downloads badge (#2352) (Jiawen Geng) [#2352](https://github.com/nodejs/node-gyp/pull/2352) +* [[`cc1cbce056`](https://github.com/nodejs/node-gyp/commit/cc1cbce056)] - **doc**: update macOS\_Catalina.md (#2293) (iMrLopez) [#2293](https://github.com/nodejs/node-gyp/pull/2293) +* [[`6287118fc4`](https://github.com/nodejs/node-gyp/commit/6287118fc4)] - **doc**: updated README.md to copy easily (#2281) (மனோஜ்குமார் பழனிச்சாமி) [#2281](https://github.com/nodejs/node-gyp/pull/2281) +* [[`66c0f04467`](https://github.com/nodejs/node-gyp/commit/66c0f04467)] - **doc**: add missing `sudo` to Catalina doc (Karl Horky) [#2244](https://github.com/nodejs/node-gyp/pull/2244) +* [[`0da2e0140d`](https://github.com/nodejs/node-gyp/commit/0da2e0140d)] - **gyp**: update gyp to v0.8.1 (#2355) (DeeDeeG) [#2355](https://github.com/nodejs/node-gyp/pull/2355) +* [[`0093ec8646`](https://github.com/nodejs/node-gyp/commit/0093ec8646)] - **gyp**: Improve our flake8 linting tests (Christian Clauss) [#2356](https://github.com/nodejs/node-gyp/pull/2356) +* [[`a78b584236`](https://github.com/nodejs/node-gyp/commit/a78b584236)] - **(SEMVER-MAJOR)** **gyp**: remove support for Python 2 (#2300) (Christian Clauss) [#2300](https://github.com/nodejs/node-gyp/pull/2300) +* [[`c3c510d89e`](https://github.com/nodejs/node-gyp/commit/c3c510d89e)] - **gyp**: update gyp to v0.8.0 (#2318) (Christian Clauss) [#2318](https://github.com/nodejs/node-gyp/pull/2318) +* [[`9e1397c52e`](https://github.com/nodejs/node-gyp/commit/9e1397c52e)] - **(SEMVER-MAJOR)** **gyp**: update gyp to v0.7.0 (#2284) (Jiawen Geng) [#2284](https://github.com/nodejs/node-gyp/pull/2284) +* [[`1bd18f3e77`](https://github.com/nodejs/node-gyp/commit/1bd18f3e77)] - **(SEMVER-MAJOR)** **lib**: drop Python 2 support in find-python.js (#2333) (DeeDeeG) [#2333](https://github.com/nodejs/node-gyp/pull/2333) +* [[`e81602ef55`](https://github.com/nodejs/node-gyp/commit/e81602ef55)] - **(SEMVER-MAJOR)** **lib**: migrate requests to fetch (#2220) (Matias Lopez) [#2220](https://github.com/nodejs/node-gyp/pull/2220) +* [[`392b7760b4`](https://github.com/nodejs/node-gyp/commit/392b7760b4)] - **lib**: avoid changing process.config (#2322) (Michaël Zasso) [#2322](https://github.com/nodejs/node-gyp/pull/2322) + +## v7.1.2 2020-10-17 * [[`096e3aded5`](https://github.com/nodejs/node-gyp/commit/096e3aded5)] - **gyp**: update gyp to 0.6.2 (Myles Borins) [#2241](https://github.com/nodejs/node-gyp/pull/2241) * [[`54f97cd243`](https://github.com/nodejs/node-gyp/commit/54f97cd243)] - **doc**: add cmd to reset `xcode-select` to initial state (Valera Rozuvan) [#2235](https://github.com/nodejs/node-gyp/pull/2235) -v7.1.1 2020-10-15 -================= +## v7.1.1 2020-10-15 This release restores the location of shared library builds to the pre-v7 location. In v7.0.0 until this release, shared library outputs were placed @@ -22,8 +367,7 @@ We consider this a bug-fix rather than semver-major change. * [[`2317dc400c`](https://github.com/nodejs/node-gyp/commit/2317dc400c)] - **ci**: switch to GitHub Actions (Shelley Vohr) [#2210](https://github.com/nodejs/node-gyp/pull/2210) * [[`2cca9b74f7`](https://github.com/nodejs/node-gyp/commit/2cca9b74f7)] - **doc**: drop the --production flag for installing windows-build-tools (DeeDeeG) [#2206](https://github.com/nodejs/node-gyp/pull/2206) -v7.1.0 2020-08-12 -================= +## v7.1.0 2020-08-12 * [[`aaf33c3029`](https://github.com/nodejs/node-gyp/commit/aaf33c3029)] - **build**: add update-gyp script (Samuel Attard) [#2167](https://github.com/nodejs/node-gyp/pull/2167) * * [[`3baa4e4172`](https://github.com/nodejs/node-gyp/commit/3baa4e4172)] - **(SEMVER-MINOR)** **gyp**: update gyp to 0.4.0 (Samuel Attard) [#2165](https://github.com/nodejs/node-gyp/pull/2165) @@ -32,8 +376,7 @@ v7.1.0 2020-08-12 * * [[`4fc8ff179d`](https://github.com/nodejs/node-gyp/commit/4fc8ff179d)] - **doc**: silence curl for macOS Catalina acid test (Chia Wei Ong) [#2150](https://github.com/nodejs/node-gyp/pull/2150) * * [[`7857cb2eb1`](https://github.com/nodejs/node-gyp/commit/7857cb2eb1)] - **deps**: increase "engines" to "node" : "\>= 10.12.0" (DeeDeeG) [#2153](https://github.com/nodejs/node-gyp/pull/2153) -v7.0.0 2020-06-03 -================= +## v7.0.0 2020-06-03 * [[`e18a61afc1`](https://github.com/nodejs/node-gyp/commit/e18a61afc1)] - **build**: shrink bloated addon binaries on windows (Shelley Vohr) [#2060](https://github.com/nodejs/node-gyp/pull/2060) * [[`4937722cf5`](https://github.com/nodejs/node-gyp/commit/4937722cf5)] - **(SEMVER-MAJOR)** **deps**: replace mkdirp with {recursive} mkdir (Rod Vagg) [#2123](https://github.com/nodejs/node-gyp/pull/2123) @@ -42,7 +385,7 @@ v7.0.0 2020-06-03 * [[`f7bfce96ed`](https://github.com/nodejs/node-gyp/commit/f7bfce96ed)] - **doc**: update acid test and introduce curl|bash test script (Dario Vladovic) [#2105](https://github.com/nodejs/node-gyp/pull/2105) * [[`e529f3309d`](https://github.com/nodejs/node-gyp/commit/e529f3309d)] - **doc**: update README to reflect upgrade to gyp-next (Ujjwal Sharma) [#2092](https://github.com/nodejs/node-gyp/pull/2092) * [[`9aed6286a3`](https://github.com/nodejs/node-gyp/commit/9aed6286a3)] - **doc**: give more attention to Catalina issues doc (Matheus Marchini) [#2134](https://github.com/nodejs/node-gyp/pull/2134) -* [[`963f2a7b48`](https://github.com/nodejs/node-gyp/commit/963f2a7b48)] - **doc**: improve cataline discoverability for search engines (Matheus Marchini) [#2135](https://github.com/nodejs/node-gyp/pull/2135) +* [[`963f2a7b48`](https://github.com/nodejs/node-gyp/commit/963f2a7b48)] - **doc**: improve Catalina discoverability for search engines (Matheus Marchini) [#2135](https://github.com/nodejs/node-gyp/pull/2135) * [[`7b75af349b`](https://github.com/nodejs/node-gyp/commit/7b75af349b)] - **doc**: add macOS Catalina software update info (Karl Horky) [#2078](https://github.com/nodejs/node-gyp/pull/2078) * [[`4f23c7bee2`](https://github.com/nodejs/node-gyp/commit/4f23c7bee2)] - **doc**: update link to the code of conduct (#2073) (Michaël Zasso) [#2073](https://github.com/nodejs/node-gyp/pull/2073) * [[`473cfa283f`](https://github.com/nodejs/node-gyp/commit/473cfa283f)] - **doc**: note in README that Python 3.8 is supported (#2072) (Michaël Zasso) [#2072](https://github.com/nodejs/node-gyp/pull/2072) @@ -60,8 +403,7 @@ v7.0.0 2020-06-03 * [[`741ab096d5`](https://github.com/nodejs/node-gyp/commit/741ab096d5)] - **test**: remove support for EOL versions of Node.js (Shelley Vohr) * [[`ca86ef2539`](https://github.com/nodejs/node-gyp/commit/ca86ef2539)] - **test**: bump actions/checkout from v1 to v2 (BSKY) [#2063](https://github.com/nodejs/node-gyp/pull/2063) -v6.1.0 2020-01-08 -================= +## v6.1.0 2020-01-08 * [[`9a7dd16b76`](https://github.com/nodejs/node-gyp/commit/9a7dd16b76)] - **doc**: remove backticks from Python version list (Rod Vagg) [#2011](https://github.com/nodejs/node-gyp/pull/2011) * [[`26cd6eaea6`](https://github.com/nodejs/node-gyp/commit/26cd6eaea6)] - **doc**: add GitHub Actions badge (#1994) (Rod Vagg) [#1994](https://github.com/nodejs/node-gyp/pull/1994) @@ -82,8 +424,7 @@ v6.1.0 2020-01-08 * [[`0670e5189d`](https://github.com/nodejs/node-gyp/commit/0670e5189d)] - **test**: add header download test (Rod Vagg) [#1796](https://github.com/nodejs/node-gyp/pull/1796) * [[`c506a6a150`](https://github.com/nodejs/node-gyp/commit/c506a6a150)] - **test**: configure proper devDir for invoking configure() (Rod Vagg) [#1796](https://github.com/nodejs/node-gyp/pull/1796) -v6.0.1 2019-11-01 -================= +## v6.0.1 2019-11-01 * [[`8ec2e681d5`](https://github.com/nodejs/node-gyp/commit/8ec2e681d5)] - **doc**: add macOS\_Catalina.md document (cclauss) [#1940](https://github.com/nodejs/node-gyp/pull/1940) * [[`1b11be63cc`](https://github.com/nodejs/node-gyp/commit/1b11be63cc)] - **gyp**: python3 fixes: utf8 decode, use of 'None' in eval (Wilfried Goesgens) [#1925](https://github.com/nodejs/node-gyp/pull/1925) @@ -100,8 +441,7 @@ v6.0.1 2019-11-01 * [[`032db2a2d0`](https://github.com/nodejs/node-gyp/commit/032db2a2d0)] - **lib,install**: always download SHA sums on Windows (Sam Hughes) [#1926](https://github.com/nodejs/node-gyp/pull/1926) * [[`5a83630c33`](https://github.com/nodejs/node-gyp/commit/5a83630c33)] - **travis**: add Windows + Python 3.8 to the mix (Rod Vagg) [#1921](https://github.com/nodejs/node-gyp/pull/1921) -v6.0.0 2019-10-04 -================= +## v6.0.0 2019-10-04 * [[`dd0e97ef0b`](https://github.com/nodejs/node-gyp/commit/dd0e97ef0b)] - **(SEMVER-MAJOR)** **lib**: try to find `python` after `python3` (Sam Roberts) [#1907](https://github.com/nodejs/node-gyp/pull/1907) * [[`f60ed47d14`](https://github.com/nodejs/node-gyp/commit/f60ed47d14)] - **travis**: add Python 3.5 and 3.6 tests on Linux (Christian Clauss) [#1903](https://github.com/nodejs/node-gyp/pull/1903) @@ -109,8 +449,7 @@ v6.0.0 2019-10-04 * [[`3d1c60ab81`](https://github.com/nodejs/node-gyp/commit/3d1c60ab81)] - **(SEMVER-MAJOR)** **lib**: accept Python 3 by default (João Reis) [#1844](https://github.com/nodejs/node-gyp/pull/1844) * [[`c6e3b65a23`](https://github.com/nodejs/node-gyp/commit/c6e3b65a23)] - **(SEMVER-MAJOR)** **lib**: raise the minimum Python version from 2.6 to 2.7 (cclauss) [#1818](https://github.com/nodejs/node-gyp/pull/1818) -v5.1.1 2020-05-25 -================= +## v5.1.1 2020-05-25 * [[`bdd3a79abe`](https://github.com/nodejs/node-gyp/commit/bdd3a79abe)] - **build**: shrink bloated addon binaries on windows (Shelley Vohr) [#2060](https://github.com/nodejs/node-gyp/pull/2060) * [[`1f2ba75bc0`](https://github.com/nodejs/node-gyp/commit/1f2ba75bc0)] - **doc**: add macOS Catalina software update info (Karl Horky) [#2078](https://github.com/nodejs/node-gyp/pull/2078) @@ -123,8 +462,7 @@ v5.1.1 2020-05-25 * [[`2b6fc3c8d6`](https://github.com/nodejs/node-gyp/commit/2b6fc3c8d6)] - **doc, bin**: stop suggesting opening node-gyp issues (Bartosz Sosnowski) [#2096](https://github.com/nodejs/node-gyp/pull/2096) * [[`a876ae58ad`](https://github.com/nodejs/node-gyp/commit/a876ae58ad)] - **test**: bump actions/checkout from v1 to v2 (BSKY) [#2063](https://github.com/nodejs/node-gyp/pull/2063) -v5.1.0 2020-02-05 -================= +## v5.1.0 2020-02-05 * [[`f37a8b40d0`](https://github.com/nodejs/node-gyp/commit/f37a8b40d0)] - **doc**: add GitHub Actions badge (#1994) (Rod Vagg) [#1994](https://github.com/nodejs/node-gyp/pull/1994) * [[`cb3f6aae5e`](https://github.com/nodejs/node-gyp/commit/cb3f6aae5e)] - **doc**: update macOS\_Catalina.md (#1992) (James Home) [#1992](https://github.com/nodejs/node-gyp/pull/1992) @@ -141,13 +479,11 @@ v5.1.0 2020-02-05 * [[`32c8744b34`](https://github.com/nodejs/node-gyp/commit/32c8744b34)] - **test**: fix macOS Travis on Python 2.7 & 3.7 (Christian Clauss) [#1979](https://github.com/nodejs/node-gyp/pull/1979) * [[`fd4b1351e4`](https://github.com/nodejs/node-gyp/commit/fd4b1351e4)] - **test**: initial Github Actions with Ubuntu & macOS (Christian Clauss) [#1985](https://github.com/nodejs/node-gyp/pull/1985) -v5.0.7 2019-12-16 -================= +## v5.0.7 2019-12-16 Republish of v5.0.6 with unnecessary tarball removed from pack file. -v5.0.6 2019-12-16 -================= +## v5.0.6 2019-12-16 * [[`cdec00286f`](https://github.com/nodejs/node-gyp/commit/cdec00286f)] - **doc**: adjustments to the README.md for new users (Dan Pike) [#1919](https://github.com/nodejs/node-gyp/pull/1919) * [[`b7c8233ef2`](https://github.com/nodejs/node-gyp/commit/b7c8233ef2)] - **test**: fix Python unittests (cclauss) [#1961](https://github.com/nodejs/node-gyp/pull/1961) @@ -168,8 +504,7 @@ v5.0.6 2019-12-16 * [[`7edf7658fa`](https://github.com/nodejs/node-gyp/commit/7edf7658fa)] - **lib,install**: always download SHA sums on Windows (Sam Hughes) [#1926](https://github.com/nodejs/node-gyp/pull/1926) * [[`69056d04fe`](https://github.com/nodejs/node-gyp/commit/69056d04fe)] - **travis**: add Windows + Python 3.8 to the mix (Rod Vagg) [#1921](https://github.com/nodejs/node-gyp/pull/1921) -v5.0.5 2019-10-04 -================= +## v5.0.5 2019-10-04 * [[`3891391746`](https://github.com/nodejs/node-gyp/commit/3891391746)] - **doc**: reconcile README with Python 3 compat changes (Rod Vagg) [#1911](https://github.com/nodejs/node-gyp/pull/1911) * [[`07f81f1920`](https://github.com/nodejs/node-gyp/commit/07f81f1920)] - **lib**: accept Python 3 after Python 2 (Sam Roberts) [#1910](https://github.com/nodejs/node-gyp/pull/1910) @@ -181,8 +516,7 @@ v5.0.5 2019-10-04 * [[`53ee7dfe89`](https://github.com/nodejs/node-gyp/commit/53ee7dfe89)] - **gyp**: fix undefined name: cflags --\> ldflags (Christian Clauss) [#1901](https://github.com/nodejs/node-gyp/pull/1901) * [[`5871dcf6c9`](https://github.com/nodejs/node-gyp/commit/5871dcf6c9)] - **src,win**: add support for fetching arm64 node.lib (Richard Townsend) [#1875](https://github.com/nodejs/node-gyp/pull/1875) -v5.0.4 2019-09-27 -================= +## v5.0.4 2019-09-27 * [[`1236869ffc`](https://github.com/nodejs/node-gyp/commit/1236869ffc)] - **gyp**: modify XcodeVersion() to convert "4.2" to "0420" and "10.0" to "1000" (Christian Clauss) [#1895](https://github.com/nodejs/node-gyp/pull/1895) * [[`36638afe48`](https://github.com/nodejs/node-gyp/commit/36638afe48)] - **gyp**: more decode stdout on Python 3 (cclauss) [#1894](https://github.com/nodejs/node-gyp/pull/1894) @@ -205,8 +539,7 @@ v5.0.4 2019-09-27 * [[`fa0ed4aa42`](https://github.com/nodejs/node-gyp/commit/fa0ed4aa42)] - **build**: more Python 3 compat, replace compile with ast (cclauss) [#1820](https://github.com/nodejs/node-gyp/pull/1820) * [[`18d5c7c9d0`](https://github.com/nodejs/node-gyp/commit/18d5c7c9d0)] - **win,src**: update win\_delay\_load\_hook.cc to work with /clr (Ivan Petrovic) [#1819](https://github.com/nodejs/node-gyp/pull/1819) -v5.0.3 2019-07-17 -================= +## v5.0.3 2019-07-17 * [[`66ad305775`](https://github.com/nodejs/node-gyp/commit/66ad305775)] - **python**: accept Python 3 conditionally (João Reis) [#1815](https://github.com/nodejs/node-gyp/pull/1815) * [[`7e7fce3fed`](https://github.com/nodejs/node-gyp/commit/7e7fce3fed)] - **python**: move Python detection to its own file (João Reis) [#1815](https://github.com/nodejs/node-gyp/pull/1815) @@ -217,8 +550,7 @@ v5.0.3 2019-07-17 * [[`24109148df`](https://github.com/nodejs/node-gyp/commit/24109148df)] - **test**: downgrade to tap@^12 for continued Node 6 support (Rod Vagg) [#1808](https://github.com/nodejs/node-gyp/pull/1808) * [[`656117cc4a`](https://github.com/nodejs/node-gyp/commit/656117cc4a)] - **win**: make VS path match case-insensitive (João Reis) [#1806](https://github.com/nodejs/node-gyp/pull/1806) -v5.0.2 2019-06-27 -================= +## v5.0.2 2019-06-27 * [[`2761afbf73`](https://github.com/nodejs/node-gyp/commit/2761afbf73)] - **build,test**: add duplicate symbol test (Gabriel Schulhof) [#1689](https://github.com/nodejs/node-gyp/pull/1689) * [[`82f129d6de`](https://github.com/nodejs/node-gyp/commit/82f129d6de)] - **gyp**: replace optparse to argparse (KiYugadgeter) [#1591](https://github.com/nodejs/node-gyp/pull/1591) @@ -237,14 +569,12 @@ v5.0.2 2019-06-27 * [[`1597c84aad`](https://github.com/nodejs/node-gyp/commit/1597c84aad)] - **test**: use Travis CI to run tests on every pull request (cclauss) [#1752](https://github.com/nodejs/node-gyp/pull/1752) * [[`dd9bf929ac`](https://github.com/nodejs/node-gyp/commit/dd9bf929ac)] - **zos**: update compiler options (Shuowang (Wayne) Zhang) [#1768](https://github.com/nodejs/node-gyp/pull/1768) -v5.0.1 2019-06-20 -================= +## v5.0.1 2019-06-20 * [[`e3861722ed`](https://github.com/nodejs/node-gyp/commit/e3861722ed)] - **doc**: document --jobs max (David Sanders) [#1770](https://github.com/nodejs/node-gyp/pull/1770) * [[`1cfdb28886`](https://github.com/nodejs/node-gyp/commit/1cfdb28886)] - **lib**: reintroduce support for iojs file naming for releases \>= 1 && \< 4 (Samuel Attard) [#1777](https://github.com/nodejs/node-gyp/pull/1777) -v5.0.0 2019-06-13 -================= +## v5.0.0 2019-06-13 * [[`8a83972743`](https://github.com/nodejs/node-gyp/commit/8a83972743)] - **(SEMVER-MAJOR)** **bin**: follow XDG OS conventions for storing data (Selwyn) [#1570](https://github.com/nodejs/node-gyp/pull/1570) * [[`9e46872ea3`](https://github.com/nodejs/node-gyp/commit/9e46872ea3)] - **bin,lib**: remove extra comments/lines/spaces (Jon Moss) [#1508](https://github.com/nodejs/node-gyp/pull/1508) @@ -282,16 +612,14 @@ v5.0.0 2019-06-13 * [[`721dc7d314`](https://github.com/nodejs/node-gyp/commit/721dc7d314)] - Add ARM64 to MSBuild /Platform logic (Jon Kunkee) [#1655](https://github.com/nodejs/node-gyp/pull/1655) * [[`a5b7410497`](https://github.com/nodejs/node-gyp/commit/a5b7410497)] - Add ESLint no-unused-vars rule (Jon Moss) [#1497](https://github.com/nodejs/node-gyp/pull/1497) -v4.0.0 2019-04-24 -================= +## v4.0.0 2019-04-24 * [[`ceed5cbe10`](https://github.com/nodejs/node-gyp/commit/ceed5cbe10)] - **deps**: updated tar package version to 4.4.8 (Pobegaylo Maksim) [#1713](https://github.com/nodejs/node-gyp/pull/1713) * [[`374519e066`](https://github.com/nodejs/node-gyp/commit/374519e066)] - **(SEMVER-MAJOR)** Upgrade to tar v3 (isaacs) [#1212](https://github.com/nodejs/node-gyp/pull/1212) * [[`e6699d13cd`](https://github.com/nodejs/node-gyp/commit/e6699d13cd)] - **test**: fix addon test for Node.js 12 and V8 7.4 (Richard Lau) [#1705](https://github.com/nodejs/node-gyp/pull/1705) * [[`0c6bf530a0`](https://github.com/nodejs/node-gyp/commit/0c6bf530a0)] - **lib**: use print() for python version detection (GreenAddress) [#1534](https://github.com/nodejs/node-gyp/pull/1534) -v3.8.0 2018-08-09 -================= +## v3.8.0 2018-08-09 * [[`c5929cb4fe`](https://github.com/nodejs/node-gyp/commit/c5929cb4fe)] - **doc**: update Xcode preferences tab name. (Ivan Daniluk) [#1330](https://github.com/nodejs/node-gyp/pull/1330) * [[`8b488da8b9`](https://github.com/nodejs/node-gyp/commit/8b488da8b9)] - **doc**: update link to commit guidelines (Jonas Hermsmeier) [#1456](https://github.com/nodejs/node-gyp/pull/1456) @@ -310,8 +638,7 @@ v3.8.0 2018-08-09 * [[`969447c5bd`](https://github.com/nodejs/node-gyp/commit/969447c5bd)] - **deps**: bump request to 2.8.7, fixes heok/hawk issues (Rohit Hazra) [#1492](https://github.com/nodejs/node-gyp/pull/1492) * [[`340403ccfe`](https://github.com/nodejs/node-gyp/commit/340403ccfe)] - **win**: improve parsing of SDK version (Alessandro Vergani) [#1516](https://github.com/nodejs/node-gyp/pull/1516) -v3.7.0 2018-06-08 -================= +## v3.7.0 2018-06-08 * [[`84cea7b30d`](https://github.com/nodejs/node-gyp/commit/84cea7b30d)] - Remove unused gyp test scripts. (Ben Noordhuis) [#1458](https://github.com/nodejs/node-gyp/pull/1458) * [[`0540e4ec63`](https://github.com/nodejs/node-gyp/commit/0540e4ec63)] - **gyp**: escape spaces in filenames in make generator (Jeff Senn) [#1436](https://github.com/nodejs/node-gyp/pull/1436) @@ -335,14 +662,12 @@ v3.7.0 2018-06-08 * [[`f27599193a`](https://github.com/nodejs/node-gyp/commit/f27599193a)] - **gyp**: update xml string encoding conversion (Liu Chao) [#1203](https://github.com/nodejs/node-gyp/pull/1203) * [[`0a07e481f7`](https://github.com/nodejs/node-gyp/commit/0a07e481f7)] - **configure**: don't set ensure if tarball is set (Gibson Fahnestock) [#1220](https://github.com/nodejs/node-gyp/pull/1220) -v3.6.3 2018-06-08 -================= +## v3.6.3 2018-06-08 * [[`90cd2e8da9`](https://github.com/nodejs/node-gyp/commit/90cd2e8da9)] - **gyp**: fix regex to match multi-digit versions (Jonas Hermsmeier) [#1455](https://github.com/nodejs/node-gyp/pull/1455) * [[`7900122337`](https://github.com/nodejs/node-gyp/commit/7900122337)] - deps: pin `request` version range (Refael Ackerman) [#1300](https://github.com/nodejs/node-gyp/pull/1300) -v3.6.2 2017-06-01 -================= +## v3.6.2 2017-06-01 * [[`72afdd62cd`](https://github.com/nodejs/node-gyp/commit/72afdd62cd)] - **build**: rename copyNodeLib() to doBuild() (Liu Chao) [#1206](https://github.com/nodejs/node-gyp/pull/1206) * [[`bad903ac70`](https://github.com/nodejs/node-gyp/commit/bad903ac70)] - **win**: more robust parsing of SDK version (Refael Ackermann) [#1198](https://github.com/nodejs/node-gyp/pull/1198) @@ -351,8 +676,7 @@ v3.6.2 2017-06-01 * [[`0913b2dd99`](https://github.com/nodejs/node-gyp/commit/0913b2dd99)] - **build, win**: use target_arch to link with node.lib (Pavel Medvedev) [#964](https://github.com/nodejs/node-gyp/pull/964) * [[`c307b302f7`](https://github.com/nodejs/node-gyp/commit/c307b302f7)] - **doc**: blorb about setting `npm_config_OPTION_NAME` (Refael Ackermann) [#1185](https://github.com/nodejs/node-gyp/pull/1185) -v3.6.1 2017-04-30 -================= +## v3.6.1 2017-04-30 * [[`49801716c2`](https://github.com/nodejs/node-gyp/commit/49801716c2)] - **test**: fix test-find-python on v0.10.x buildbot. (Ben Noordhuis) [#1172](https://github.com/nodejs/node-gyp/pull/1172) * [[`a83a3801fc`](https://github.com/nodejs/node-gyp/commit/a83a3801fc)] - **test**: fix test/test-configure-python on AIX (Richard Lau) [#1131](https://github.com/nodejs/node-gyp/pull/1131) @@ -360,8 +684,7 @@ v3.6.1 2017-04-30 * [[`c09cf7671e`](https://github.com/nodejs/node-gyp/commit/c09cf7671e)] - **doc**: add a note for using `configure` on Windows (Vse Mozhet Byt) [#1152](https://github.com/nodejs/node-gyp/pull/1152) * [[`da9cb5f411`](https://github.com/nodejs/node-gyp/commit/da9cb5f411)] - Delete superfluous .patch files. (Ben Noordhuis) [#1122](https://github.com/nodejs/node-gyp/pull/1122) -v3.6.0 2017-03-16 -================= +## v3.6.0 2017-03-16 * [[`ae141e1906`](https://github.com/nodejs/node-gyp/commit/ae141e1906)] - **win**: find and setup for VS2017 (Refael Ackermann) [#1130](https://github.com/nodejs/node-gyp/pull/1130) * [[`ec5fc36a80`](https://github.com/nodejs/node-gyp/commit/ec5fc36a80)] - Add support to build node.js with chakracore for ARM. (Kunal Pathak) [#873](https://github.com/nodejs/node-gyp/pull/873) @@ -369,9 +692,7 @@ v3.6.0 2017-03-16 * [[`93d7fa83c8`](https://github.com/nodejs/node-gyp/commit/93d7fa83c8)] - Upgrade semver dependency. (Ben Noordhuis) [#1107](https://github.com/nodejs/node-gyp/pull/1107) * [[`ff9a6fadfd`](https://github.com/nodejs/node-gyp/commit/ff9a6fadfd)] - Update link of gyp as Google code is shutting down (Peter Dave Hello) [#1061](https://github.com/nodejs/node-gyp/pull/1061) - -v3.5.0 2017-01-10 -================= +## v3.5.0 2017-01-10 * [[`762d19a39e`](https://github.com/nodejs/node-gyp/commit/762d19a39e)] - \[doc\] merge History.md and CHANGELOG.md (Rod Vagg) * [[`80fc5c3d31`](https://github.com/nodejs/node-gyp/commit/80fc5c3d31)] - Fix deprecated dependency warning (Simone Primarosa) [#1069](https://github.com/nodejs/node-gyp/pull/1069) @@ -385,8 +706,7 @@ v3.5.0 2017-01-10 * [[`9c8d275526`](https://github.com/nodejs/node-gyp/commit/9c8d275526)] - Add --devdir flag. (Ben Noordhuis) [#916](https://github.com/nodejs/node-gyp/pull/916) * [[`f6eab1f9e4`](https://github.com/nodejs/node-gyp/commit/f6eab1f9e4)] - **doc**: add windows-build-tools to readme (Felix Rieseberg) [#970](https://github.com/nodejs/node-gyp/pull/970) -v3.4.0 2016-06-28 -================= +## v3.4.0 2016-06-28 * [[`ce5fd04e94`](https://github.com/nodejs/node-gyp/commit/ce5fd04e94)] - **deps**: update minimatch version (delphiactual) [#961](https://github.com/nodejs/node-gyp/pull/961) * [[`77383ddd85`](https://github.com/nodejs/node-gyp/commit/77383ddd85)] - Replace fs.accessSync call to fs.statSync (Richard Lau) [#955](https://github.com/nodejs/node-gyp/pull/955) @@ -406,13 +726,11 @@ v3.4.0 2016-06-28 * [[`625c1515f9`](https://github.com/nodejs/node-gyp/commit/625c1515f9)] - **gyp**: inherit CC/CXX for CC/CXX.host (Johan Bergström) [#908](https://github.com/nodejs/node-gyp/pull/908) * [[`3bcb1720e4`](https://github.com/nodejs/node-gyp/commit/3bcb1720e4)] - Add support for the Python launcher on Windows (Patrick Westerhoff) [#894](https://github.com/nodejs/node-gyp/pull/894 -v3.3.1 2016-03-04 -================= +## v3.3.1 2016-03-04 * [[`a981ef847a`](https://github.com/nodejs/node-gyp/commit/a981ef847a)] - **gyp**: fix android generator (Robert Chiras) [#889](https://github.com/nodejs/node-gyp/pull/889) -v3.3.0 2016-02-16 -================= +## v3.3.0 2016-02-16 * [[`818d854a4d`](https://github.com/nodejs/node-gyp/commit/818d854a4d)] - Introduce NODEJS_ORG_MIRROR and IOJS_ORG_MIRROR (Rod Vagg) [#878](https://github.com/nodejs/node-gyp/pull/878) * [[`d1e4cc4b62`](https://github.com/nodejs/node-gyp/commit/d1e4cc4b62)] - **(SEMVER-MINOR)** Download headers tarball for ~0.12.10 || ~0.10.42 (Rod Vagg) [#877](https://github.com/nodejs/node-gyp/pull/877) @@ -421,14 +739,12 @@ v3.3.0 2016-02-16 * [[`8c4b0ffa50`](https://github.com/nodejs/node-gyp/commit/8c4b0ffa50)] - **(SEMVER-MINOR)** Add --cafile command line option. (Ben Noordhuis) [#837](https://github.com/nodejs/node-gyp/pull/837) * [[`b3ad43498e`](https://github.com/nodejs/node-gyp/commit/b3ad43498e)] - **(SEMVER-MINOR)** Make download() function testable. (Ben Noordhuis) [#837](https://github.com/nodejs/node-gyp/pull/837) -v3.2.1 2015-12-03 -================= +## v3.2.1 2015-12-03 * [[`ab89b477c4`](https://github.com/nodejs/node-gyp/commit/ab89b477c4)] - Upgrade gyp to b3cef02. (Ben Noordhuis) [#831](https://github.com/nodejs/node-gyp/pull/831) * [[`90078ecb17`](https://github.com/nodejs/node-gyp/commit/90078ecb17)] - Define WIN32_LEAN_AND_MEAN conditionally. (Ben Noordhuis) [#824](https://github.com/nodejs/node-gyp/pull/824) -v3.2.0 2015-11-25 -================= +## v3.2.0 2015-11-25 * [[`268f1ca4c7`](https://github.com/nodejs/node-gyp/commit/268f1ca4c7)] - Use result of `which` when searching for python. (Refael Ackermann) [#668](https://github.com/nodejs/node-gyp/pull/668) * [[`817ed9bd78`](https://github.com/nodejs/node-gyp/commit/817ed9bd78)] - Add test for python executable search logic. (Ben Noordhuis) [#756](https://github.com/nodejs/node-gyp/pull/756) @@ -437,8 +753,7 @@ v3.2.0 2015-11-25 * [[`a8d441a0a2`](https://github.com/nodejs/node-gyp/commit/a8d441a0a2)] - Update README for Windows 10 support. (Jason Williams) [#766](https://github.com/nodejs/node-gyp/pull/766) * [[`d1d6015276`](https://github.com/nodejs/node-gyp/commit/d1d6015276)] - Update broken links and switch to HTTPS. (andrew morton) -v3.1.0 2015-11-14 -================= +## v3.1.0 2015-11-14 * [[`9049241f91`](https://github.com/nodejs/node-gyp/commit/9049241f91)] - **gyp**: don't use links at all, just copy the files instead (Nathan Zadoks) * [[`8ef90348d1`](https://github.com/nodejs/node-gyp/commit/8ef90348d1)] - **gyp**: apply https://codereview.chromium.org/11361103/ (Nathan Rajlich) @@ -448,24 +763,20 @@ v3.1.0 2015-11-14 * [[`2ac7de02c4`](https://github.com/nodejs/node-gyp/commit/2ac7de02c4)] - Fix infinite loop with zero-length options. (Ben Noordhuis) [#745](https://github.com/nodejs/node-gyp/pull/745) * [[`101bed639b`](https://github.com/nodejs/node-gyp/commit/101bed639b)] - This platform value came from debian package, and now the value (Jérémy Lal) [#738](https://github.com/nodejs/node-gyp/pull/738) -v3.0.3 2015-09-14 -================= +## v3.0.3 2015-09-14 * [[`ad827cda30`](https://github.com/nodejs/node-gyp/commit/ad827cda30)] - tarballUrl global and && when checking for iojs (Lars-Magnus Skog) [#729](https://github.com/nodejs/node-gyp/pull/729) -v3.0.2 2015-09-12 -================= +## v3.0.2 2015-09-12 * [[`6e8c3bf3c6`](https://github.com/nodejs/node-gyp/commit/6e8c3bf3c6)] - add back support for passing additional cmdline args (Rod Vagg) [#723](https://github.com/nodejs/node-gyp/pull/723) * [[`ff82f2f3b9`](https://github.com/nodejs/node-gyp/commit/ff82f2f3b9)] - fixed broken link in docs to Visual Studio 2013 download (simon-p-r) [#722](https://github.com/nodejs/node-gyp/pull/722) -v3.0.1 2015-09-08 -================= +## v3.0.1 2015-09-08 * [[`846337e36b`](https://github.com/nodejs/node-gyp/commit/846337e36b)] - normalise versions for target == this comparison (Rod Vagg) [#716](https://github.com/nodejs/node-gyp/pull/716) -v3.0.0 2015-09-08 -================= +## v3.0.0 2015-09-08 * [[`9720d0373c`](https://github.com/nodejs/node-gyp/commit/9720d0373c)] - remove node_modules from tree (Rod Vagg) [#711](https://github.com/nodejs/node-gyp/pull/711) * [[`6dcf220db7`](https://github.com/nodejs/node-gyp/commit/6dcf220db7)] - test version major directly, don't use semver.satisfies() (Rod Vagg) [#711](https://github.com/nodejs/node-gyp/pull/711) @@ -477,8 +788,7 @@ v3.0.0 2015-09-08 * [[`85ed107565`](https://github.com/nodejs/node-gyp/commit/85ed107565)] - Merge pull request #664 from othiym23/othiym23/allow-semver-5 (Nathan Rajlich) * [[`0c720d234c`](https://github.com/nodejs/node-gyp/commit/0c720d234c)] - allow semver@5 (Forrest L Norvell) -2.0.2 / 2015-07-14 -================== +## 2.0.2 / 2015-07-14 * Use HTTPS for dist url (#656, @SonicHedgehog) * Merge pull request #648 from nevosegal/master @@ -491,14 +801,12 @@ v3.0.0 2015-09-08 src/win_delay_load_hook.c, and fixes of the long relative path issue on Win32. Fixes #636 (#637, @lygstate). -2.0.1 / 2015-05-28 -================== +## 2.0.1 / 2015-05-28 * configure: try/catch the semver range.test() call * README: update for visual studio 2013 (#510, @samccone) -2.0.0 / 2015-05-24 -================== +## 2.0.0 / 2015-05-24 * configure: check for python2 executable by default, fallback to python * configure: don't clobber existing $PYTHONPATH diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c1c50eab4e..5b977898f1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ ## Code of Conduct Please read the -[Code of Conduct](https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md) +[Code of Conduct](https://github.com/nodejs/admin/blob/main/CODE_OF_CONDUCT.md) which explains the minimum behavior expectations for node-gyp contributors. diff --git a/README.md b/README.md index 64e82dbbe3..f46ee06308 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # `node-gyp` - Node.js native addon build tool -[![Build Status](https://github.com/nodejs/node-gyp/workflows/Tests/badge.svg?branch=master)](https://github.com/nodejs/node-gyp/actions?query=workflow%3ATests+branch%3Amaster) +[![Build Status](https://github.com/nodejs/node-gyp/workflows/Tests/badge.svg?branch=main)](https://github.com/nodejs/node-gyp/actions?query=workflow%3ATests+branch%3Amain) +![npm](https://img.shields.io/npm/dm/node-gyp) `node-gyp` is a cross-platform command-line tool written in Node.js for compiling native addon modules for Node.js. It contains a vendored copy of the [gyp-next](https://github.com/nodejs/gyp-next) project that was previously used -by the Chromium team, extended to support the development of Node.js native addons. +by the Chromium team and extended to support the development of Node.js native +addons. Note that `node-gyp` is _not_ used to build Node.js itself. @@ -30,43 +32,39 @@ Depending on your operating system, you will need to install: ### On Unix - * Python v2.7, v3.5, v3.6, v3.7, or v3.8 + * [A supported version of Python](https://devguide.python.org/versions/) * `make` * A proper C/C++ compiler toolchain, like [GCC](https://gcc.gnu.org) ### On macOS -**ATTENTION**: If your Mac has been _upgraded_ to macOS Catalina (10.15), please read [macOS_Catalina.md](macOS_Catalina.md). + * [A supported version of Python](https://devguide.python.org/versions/) + * `Xcode Command Line Tools` which will install `clang`, `clang++`, and `make`. + * Install the `Xcode Command Line Tools` standalone by running `xcode-select --install`. -- OR -- + * Alternatively, if you already have the [full Xcode installed](https://developer.apple.com/xcode/download/), you can install the Command Line Tools under the menu `Xcode -> Open Developer Tool -> More Developer Tools...`. - * Python v2.7, v3.5, v3.6, v3.7, or v3.8 - * [Xcode](https://developer.apple.com/xcode/download/) - * You also need to install the `XCode Command Line Tools` by running `xcode-select --install`. Alternatively, if you already have the full Xcode installed, you can find them under the menu `Xcode -> Open Developer Tool -> More Developer Tools...`. This step will install `clang`, `clang++`, and `make`. ### On Windows -Install the current version of Python from the [Microsoft Store package](https://docs.python.org/3/using/windows.html#the-microsoft-store-package). - -#### Option 1 - -Install all the required tools and configurations using Microsoft's [windows-build-tools](https://github.com/felixrieseberg/windows-build-tools) using `npm install --global windows-build-tools` from an elevated PowerShell or CMD.exe (run as Administrator). - -#### Option 2 +Install the current [version of Python](https://devguide.python.org/versions/) from the +[Microsoft Store](https://apps.microsoft.com/store/search?publisher=Python+Software+Foundation). Install tools and configuration manually: * Install Visual C++ Build Environment: [Visual Studio Build Tools](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools) - (using "Visual C++ build tools" workload) or [Visual Studio 2017 Community](https://visualstudio.microsoft.com/pl/thank-you-downloading-visual-studio/?sku=Community) + (using "Visual C++ build tools" if using a version older than VS2019, otherwise use "Desktop development with C++" workload) or [Visual Studio Community](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) (using the "Desktop development with C++" workload) - * Launch cmd, `npm config set msvs_version 2017` If the above steps didn't work for you, please visit [Microsoft's Node.js Guidelines for Windows](https://github.com/Microsoft/nodejs-guidelines/blob/master/windows-environment.md#compiling-native-addon-modules) for additional tips. - To target native ARM64 Node.js on Windows 10 on ARM, add the components "Visual C++ compilers and libraries for ARM64" and "Visual C++ ATL for ARM64". + To target native ARM64 Node.js on Windows on ARM, add the components "Visual C++ compilers and libraries for ARM64" and "Visual C++ ATL for ARM64". + + To use the native ARM64 C++ compiler on Windows on ARM, ensure that you have Visual Studio 2022 [17.4 or later](https://devblogs.microsoft.com/visualstudio/arm64-visual-studio-is-officially-here/) installed. ### Configuring Python Dependency -`node-gyp` requires that you have installed a compatible version of Python, one of: v2.7, v3.5, v3.6, -v3.7, or v3.8. If you have multiple Python versions installed, you can identify which Python -version `node-gyp` should use in one of the following ways: +`node-gyp` requires that you have installed a [supported version of Python](https://devguide.python.org/versions/). +If you have multiple versions of Python installed, you can identify which version +`node-gyp` should use in one of the following ways: 1. by setting the `--python` command-line option, e.g.: @@ -75,24 +73,44 @@ node-gyp --python /path/to/executable/python ``` 2. If `node-gyp` is called by way of `npm`, *and* you have multiple versions of -Python installed, then you can set `npm`'s 'python' config key to the appropriate -value: - +Python installed, then you can set the `npm_config_python` environment variable +to the appropriate path: ``` bash -npm config set python /path/to/executable/python +export npm_config_python=/path/to/executable/python +``` +    Or on Windows: +```console +py --list-paths # To see the installed Python versions +set npm_config_python=C:\path\to\python.exe ``` 3. If the `PYTHON` environment variable is set to the path of a Python executable, -then that version will be used, if it is a compatible version. +then that version will be used if it is a supported version. 4. If the `NODE_GYP_FORCE_PYTHON` environment variable is set to the path of a Python executable, it will be used instead of any of the other configured or -builtin Python search paths. If it's not a compatible version, no further +built-in Python search paths. If it's not a compatible version, no further searching will be done. +### Build for Third Party Node.js Runtimes + +When building modules for third-party Node.js runtimes like Electron, which have +different build configurations from the official Node.js distribution, you +should use `--dist-url` or `--nodedir` flags to specify the headers of the +runtime to build for. + +Also when `--dist-url` or `--nodedir` flags are passed, node-gyp will use the +`config.gypi` shipped in the headers distribution to generate build +configurations, which is different from the default mode that would use the +`process.config` object of the running Node.js instance. + +Some old versions of Electron shipped malformed `config.gypi` in their headers +distributions, and you might need to pass `--force-process-config` to node-gyp +to work around configuration errors. + ## How to Use -To compile your native addon, first go to its root directory: +To compile your native addon first go to its root directory: ``` bash cd my_node_addon @@ -149,13 +167,15 @@ A barebones `gyp` file appropriate for building a Node.js addon could look like: ## Further reading +The **[docs](./docs/)** directory contains additional documentation on specific node-gyp topics that may be useful if you are experiencing problems installing or building addons using node-gyp. + Some additional resources for Node.js native addons and writing `gyp` configuration files: * ["Going Native" a nodeschool.io tutorial](http://nodeschool.io/#goingnative) - * ["Hello World" node addon example](https://github.com/nodejs/node/tree/master/test/addons/hello-world) + * ["Hello World" node addon example](https://github.com/nodejs/node/tree/main/test/addons/hello-world) * [gyp user documentation](https://gyp.gsrc.io/docs/UserDocumentation.md) * [gyp input format reference](https://gyp.gsrc.io/docs/InputFormatReference.md) - * [*"binding.gyp" files out in the wild* wiki page](https://github.com/nodejs/node-gyp/wiki/%22binding.gyp%22-files-out-in-the-wild) + * [*"binding.gyp" files out in the wild* wiki page](./docs/binding.gyp-files-in-the-wild.md) ## Commands @@ -201,6 +221,7 @@ Some additional resources for Node.js native addons and writing `gyp` configurat | `--python=$path` | Set path to the Python binary | `--msvs_version=$version` | Set Visual Studio version (Windows only) | `--solution=$solution` | Set Visual Studio Solution version (Windows only) +| `--force-process-config` | Force using runtime's `process.config` object to generate `config.gypi` file ## Configuration @@ -223,7 +244,7 @@ Or this on Windows: set npm_config_devdir=c:\temp\.gyp ``` -### `npm` configuration +### `npm` configuration for npm versions before v9 Use the form `OPTION_NAME` for any of the command options listed above. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..1e168d76e3 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,2 @@ +If you believe you have found a security issue in the software in this +repository, please consult https://github.com/nodejs/node/blob/HEAD/SECURITY.md. \ No newline at end of file diff --git a/addon.gypi b/addon.gypi index 9327b0d722..b4ac369acb 100644 --- a/addon.gypi +++ b/addon.gypi @@ -103,22 +103,41 @@ '-Wl,-bimport:<(node_exp_file)' ], }], + [ 'OS=="os400"', { + 'ldflags': [ + '-Wl,-bimport:<(node_exp_file)' + ], + }], [ 'OS=="zos"', { - 'cflags': [ - '-q64', - '-Wc,DLL', - '-qlonglong', - '-qenum=int', - '-qxclang=-fexec-charset=ISO8859-1' + 'conditions': [ + [ '" 0) { versions.forEach(function (version) { console.log(version) @@ -120,7 +120,7 @@ process.on('uncaughtException', function (err) { function errorMessage () { // copied from npm's lib/utils/error-handler.js - var os = require('os') + const os = require('os') log.error('System', os.type() + ' ' + os.release()) log.error('command', process.argv .map(JSON.stringify).join(' ')) diff --git a/docs/Error-pre-versions-of-node-cannot-be-installed.md b/docs/Error-pre-versions-of-node-cannot-be-installed.md new file mode 100644 index 0000000000..c1e1158d70 --- /dev/null +++ b/docs/Error-pre-versions-of-node-cannot-be-installed.md @@ -0,0 +1,94 @@ +When using `node-gyp` you might see an error like this when attempting to compile/install a node.js native addon: + +``` +$ npm install bcrypt +npm http GET https://registry.npmjs.org/bcrypt/0.7.5 +npm http 304 https://registry.npmjs.org/bcrypt/0.7.5 +npm http GET https://registry.npmjs.org/bindings/1.0.0 +npm http 304 https://registry.npmjs.org/bindings/1.0.0 + +> bcrypt@0.7.5 install /home/ubuntu/public/song-swap/node_modules/bcrypt +> node-gyp rebuild + +gyp ERR! configure error +gyp ERR! stack Error: "pre" versions of node cannot be installed, use the --nodedir flag instead +gyp ERR! stack at install (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/install.js:69:16) +gyp ERR! stack at Object.self.commands.(anonymous function) [as install] (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/node-gyp.js:56:37) +gyp ERR! stack at getNodeDir (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:219:20) +gyp ERR! stack at /usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:105:9 +gyp ERR! stack at ChildProcess.exithandler (child_process.js:630:7) +gyp ERR! stack at ChildProcess.EventEmitter.emit (events.js:99:17) +gyp ERR! stack at maybeClose (child_process.js:730:16) +gyp ERR! stack at Process.ChildProcess._handle.onexit (child_process.js:797:5) +gyp ERR! System Linux 3.5.0-21-generic +gyp ERR! command "node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild" +gyp ERR! cwd /home/ubuntu/public/song-swap/node_modules/bcrypt +gyp ERR! node -v v0.11.2-pre +gyp ERR! node-gyp -v v0.9.5 +gyp ERR! not ok +npm ERR! bcrypt@0.7.5 install: `node-gyp rebuild` +npm ERR! `sh "-c" "node-gyp rebuild"` failed with 1 +npm ERR! +npm ERR! Failed at the bcrypt@0.7.5 install script. +npm ERR! This is most likely a problem with the bcrypt package, +npm ERR! not with npm itself. +npm ERR! Tell the author that this fails on your system: +npm ERR! node-gyp rebuild +npm ERR! You can get their info via: +npm ERR! npm owner ls bcrypt +npm ERR! There is likely additional logging output above. + +npm ERR! System Linux 3.5.0-21-generic +npm ERR! command "/usr/local/bin/node" "/usr/local/bin/npm" "install" "bcrypt" +npm ERR! cwd /home/ubuntu/public/song-swap +npm ERR! node -v v0.11.2-pre +npm ERR! npm -v 1.2.18 +npm ERR! code ELIFECYCLE +npm ERR! +npm ERR! Additional logging details can be found in: +npm ERR! /home/ubuntu/public/song-swap/npm-debug.log +npm ERR! not ok code 0 +``` + +The main error here is: + +``` +Error: "pre" versions of node cannot be installed, use the --nodedir flag instead +``` + +This error is caused when you attempt to compile a native addon using a version of node.js with `-pre` at the end of the version number: + +``` bash +$ node -v +v0.10.4-pre +``` + +## How to avoid (the short answer) + +To avoid this error completely just use a stable release of node.js. i.e. `v0.10.4`, and __not__ `v0.10.4-pre`. + +## How to fix (the long answer) + +This error happens because `node-gyp` does not know what header files were used to compile your "pre" version of node, and therefore it needs you to specify the node source code directory path using the `--nodedir` flag. + +For example, if I compiled my development ("pre") version of node.js using the source code in `/Users/nrajlich/node`, then I could invoke `node-gyp` like: + +``` bash +$ node-gyp rebuild --nodedir=/Users/nrajlich/node +``` + +Or install an native addon through `npm` like: + +``` bash +$ npm install bcrypt --nodedir=/Users/nrajlich/node +``` + +### Always use `--nodedir` + +__Note:__ This is for advanced users who use `-pre` versions of node more often than tagged releases. + +If you're invoking `node-gyp` through `npm`, then you can leverage `npm`'s configuration system and not have to specify the `--nodedir` flag all the time: + +``` bash +$ npm config set nodedir /Users/nrajlich/node +``` \ No newline at end of file diff --git a/docs/Force-npm-to-use-global-node-gyp.md b/docs/Force-npm-to-use-global-node-gyp.md new file mode 100644 index 0000000000..c6304e490a --- /dev/null +++ b/docs/Force-npm-to-use-global-node-gyp.md @@ -0,0 +1,47 @@ +# Force npm to use global installed node-gyp + +**Note: These instructions only work with npm 6 or older. For a solution that works with npm 8 (or older), see [Updating-npm-bundled-node-gyp.md](Updating-npm-bundled-node-gyp.md).** + +[Many issues](https://github.com/nodejs/node-gyp/labels/ERR%21%20node-gyp%20-v%20%3C%3D%20v5.1.0) are opened by users who are +not running a [current version of node-gyp](https://github.com/nodejs/node-gyp/releases). + +npm bundles its own, internal, copy of node-gyp located at `npm/node_modules`, within npm's private dependencies which are separate from *globally* accessible packages. Therefore this internal copy of node-gyp is independent from any globally installed copy of node-gyp that +may have been installed via `npm install -g node-gyp`. + +So npm's internal copy of node-gyp **isn't** stored inside *global* `node_modules` and thus isn't available for use as a standalone package. npm uses it's *internal* copy of `node-gyp` to automatically build native addons. + +When you install a _new_ version of node-gyp outside of npm, it'll go into your *global* `node_modules`, but not under the `npm/node_modules` (where internal copy of node-gyp is stored). So it will get into your `$PATH` and you will be able to use this globally installed version (**but not internal node-gyp of npm**) as any other globally installed package. + +The catch is that npm **won't** use global version unless you tell it to, it'll keep on using the **internal one**. You need to instruct it to by setting the `node_gyp` config variable (which goes into your `~/.npmrc`). You do this by running the `npm config set` command as below. Then npm will use the command in the path you supply whenever it needs to build a native addon. + +**Important**: You also need to remember to unset this when you upgrade npm with a newer version of node-gyp, or you have to manually keep your globally installed node-gyp to date. See "Undo" below. + +## Linux and macOS +``` +npm install --global node-gyp@latest +npm config set node_gyp $(npm prefix -g)/lib/node_modules/node-gyp/bin/node-gyp.js +``` + +`sudo` may be required for the first command if you get a permission error. + +## Windows + +### Windows Command Prompt +``` +npm install --global node-gyp@latest +for /f "delims=" %P in ('npm prefix -g') do npm config set node_gyp "%P\node_modules\node-gyp\bin\node-gyp.js" +``` + +### Powershell +``` +npm install --global node-gyp@latest +npm prefix -g | % {npm config set node_gyp "$_\node_modules\node-gyp\bin\node-gyp.js"} +``` + +## Undo +**Beware** if you don't unset the `node_gyp` config option, npm will continue to use the globally installed version of node-gyp rather than the one it ships with, which may end up being newer. + +``` +npm config delete node_gyp +npm uninstall --global node-gyp +``` diff --git a/docs/Home.md b/docs/Home.md new file mode 100644 index 0000000000..fe099868b2 --- /dev/null +++ b/docs/Home.md @@ -0,0 +1,7 @@ +Welcome to the node-gyp wiki! + + * [["binding.gyp" files out in the wild]] + * [[Linking to OpenSSL]] + * [[Common Issues]] + * [[Updating npm's bundled node-gyp]] + * [[Error: "pre" versions of node cannot be installed]] diff --git a/docs/Linking-to-OpenSSL.md b/docs/Linking-to-OpenSSL.md new file mode 100644 index 0000000000..ec80929995 --- /dev/null +++ b/docs/Linking-to-OpenSSL.md @@ -0,0 +1,86 @@ +A handful of native addons require linking to OpenSSL in one way or another. This introduces a small challenge since node will sometimes bundle OpenSSL statically (the default for node >= v0.8.x), or sometimes dynamically link to the system OpenSSL (default for node <= v0.6.x). + +Good native addons should account for both scenarios. It's recommended that you use the `binding.gyp` file provided below as a starting-point for any addon that needs to use OpenSSL: + +``` python +{ + 'variables': { + # node v0.6.x doesn't give us its build variables, + # but on Unix it was only possible to use the system OpenSSL library, + # so default the variable to "true", v0.8.x node and up will overwrite it. + 'node_shared_openssl%': 'true' + }, + 'targets': [ + { + 'target_name': 'binding', + 'sources': [ + 'src/binding.cc' + ], + 'conditions': [ + ['node_shared_openssl=="false"', { + # so when "node_shared_openssl" is "false", then OpenSSL has been + # bundled into the node executable. So we need to include the same + # header files that were used when building node. + 'include_dirs': [ + '<(node_root_dir)/deps/openssl/openssl/include' + ], + "conditions" : [ + ["target_arch=='ia32'", { + "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ] + }], + ["target_arch=='x64'", { + "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ] + }], + ["target_arch=='arm'", { + "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ] + }] + ] + }] + ] + } + ] +} +``` + +This ensures that when OpenSSL is statically linked into `node` then, the bundled OpenSSL headers are included, but when the system OpenSSL is in use, then only those headers will be used. + +## Windows? + +As you can see this baseline `binding.gyp` file only accounts for the Unix scenario. Currently on Windows the situation is a little less ideal. On Windows, OpenSSL is _always_ statically compiled into the `node` executable, so ideally it would be possible to use that copy of OpenSSL when building native addons. + +Unfortunately it doesn't seem like that is possible at the moment, as there would need to be tweaks made to the generated `node.lib` file to include the openssl glue functions, or a new `openssl.lib` file would need to be created during the node build. I'm not sure which is the easiest/most feasible. + +In the meantime, one possible solution is using another copy of OpenSSL, which is what [`node-bcrypt`](https://github.com/ncb000gt/node.bcrypt.js) currently does. Adding something like this to your `binding.gyp` file's `"conditions"` block would enable this: + +``` python + [ 'OS=="win"', { + 'conditions': [ + # "openssl_root" is the directory on Windows of the OpenSSL files. + # Check the "target_arch" variable to set good default values for + # both 64-bit and 32-bit builds of the module. + ['target_arch=="x64"', { + 'variables': { + 'openssl_root%': 'C:/OpenSSL-Win64' + }, + }, { + 'variables': { + 'openssl_root%': 'C:/OpenSSL-Win32' + }, + }], + ], + 'libraries': [ + '-l<(openssl_root)/lib/libeay32.lib', + ], + 'include_dirs': [ + '<(openssl_root)/include', + ], + }] +``` + +Now you can direct your users to install OpenSSL on Windows from here (be sure to tell them to install the 64-bit version if they're compiling against a 64-bit version of node): http://slproweb.com/products/Win32OpenSSL.html + +Also note that both `node-gyp` and `npm` allow you to overwrite that default `openssl_root` variable on the command line: + +``` bash +$ node-gyp rebuild --openssl-root="C:\Users\Nathan\Desktop\openssl" +``` \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..3b8c86179d --- /dev/null +++ b/docs/README.md @@ -0,0 +1,19 @@ +## Versions of `node-gyp` that are earlier than v9.x.x + +Please look thru your error log for the string `gyp info using node-gyp@` and if that version number is less than the [current release of node-gyp](https://github.com/nodejs/node-gyp/releases) then __please upgrade__ using [these instructions](https://github.com/nodejs/node-gyp/blob/main/docs/Updating-npm-bundled-node-gyp.md) and then try your command again. + +## `node-sass` is deprecated + +Please be aware that the package [`node-sass` is deprecated](https://github.com/sass/node-sass#node-sass) so you should actively seek alternatives. You can try: +``` +npm uninstall node-sass +npm install sass --save +# or ... +npm install --global node-sass@latest +``` +`node-sass` projects _may_ work by downgrading to Node.js v14 but [that release is end-of-life](https://github.com/nodejs/release#release-schedule). +But in any case, please avoid opening new `node-sass` issues on this repo because we [cannot help much](https://github.com/nodejs/node-gyp/issues?q=is%3Aissue+label%3A%22Node+Sass+--%3E+Dart+Sass%22+). + +## Issues finding the installed Visual Studio + +In cmd, [`npm config set msvs_version 20xx`](https://github.com/nodejs/node-gyp#on-windows) with ___xx___ matching your locally installed version of Visual Studio. diff --git a/docs/Updating-npm-bundled-node-gyp.md b/docs/Updating-npm-bundled-node-gyp.md new file mode 100644 index 0000000000..5759add3fe --- /dev/null +++ b/docs/Updating-npm-bundled-node-gyp.md @@ -0,0 +1,72 @@ +# Updating the npm-bundled version of node-gyp + +**Note: These instructions are (only) tested and known to work with npm 8 and older.** + +**Note: These instructions will be undone if you reinstall or upgrade npm or node! For a more permanent (and simpler) solution, see [Force-npm-to-use-global-node-gyp.md](Force-npm-to-use-global-node-gyp.md). (npm 6 or older only!)** + +[Many issues](https://github.com/nodejs/node-gyp/issues?q=label%3A"ERR!+node-gyp+-v+<%3D+v9.x.x") are opened by users who are +not running a [current version of node-gyp](https://github.com/nodejs/node-gyp/releases). + +`npm` bundles its own, internal, copy of `node-gyp`. This internal copy is independent of any globally installed copy of node-gyp that +may have been installed via `npm install -g node-gyp`. + +This means that while `node-gyp` doesn't get installed into your `$PATH` by default, npm still keeps its own copy to invoke when you +attempt to `npm install` a native add-on. + +Sometimes, you may need to update npm's internal node-gyp to a newer version than what is installed. A simple `npm install -g node-gyp` +_won't_ do the trick since npm will still continue to use its internal copy over the global one. + +So instead: + +## Version of npm + +We need to start by knowing your version of `npm`: +```bash +npm --version +``` + +## Linux, macOS, Solaris, etc. + +Unix is easy. Just run the following command. + +If your npm is version ___7 or 8___, do: +```bash +$ npm explore npm/node_modules/@npmcli/run-script -g -- npm_config_global=false npm install node-gyp@latest +``` + +Else if your npm is version ___less than 7___, do: +```bash +$ npm explore npm/node_modules/npm-lifecycle -g -- npm install node-gyp@latest +``` + +If the command fails with a permissions error, please try `sudo` and then the command. + +## Windows + +Windows is a bit trickier, since `npm` might be installed to the "Program Files" directory, which needs admin privileges in order to +modify on current Windows. Therefore, run the following commands __inside a `cmd.exe` started with "Run as Administrator"__: + +First we need to find the location of `node`. If you don't already know the location that `node.exe` got installed to, then run: +```bash +$ where node +``` + +Now `cd` to the directory that `node.exe` is contained in e.g.: +```bash +$ cd "C:\Program Files\nodejs" +``` + +If your npm version is ___7 or 8___, do: +```bash +cd node_modules\npm\node_modules\@npmcli\run-script +``` + +Else if your npm version is ___less than 7___, do: +```bash +cd node_modules\npm\node_modules\npm-lifecycle +``` + +Finish by running: +```bash +$ npm install node-gyp@latest +``` diff --git a/docs/binding.gyp-files-in-the-wild.md b/docs/binding.gyp-files-in-the-wild.md new file mode 100644 index 0000000000..795d2fd2ec --- /dev/null +++ b/docs/binding.gyp-files-in-the-wild.md @@ -0,0 +1,49 @@ +This page contains links to some examples of existing `binding.gyp` files that other node modules are using. Take a look at them for inspiration. + +To add to this page, just add the link to the project's `binding.gyp` file below: + + * [ons](https://github.com/XadillaX/aliyun-ons/blob/master/binding.gyp) + * [thmclrx](https://github.com/XadillaX/thmclrx/blob/master/binding.gyp) + * [libxmljs](https://github.com/polotek/libxmljs/blob/master/binding.gyp) + * [node-buffertools](https://github.com/bnoordhuis/node-buffertools/blob/master/binding.gyp) + * [node-canvas](https://github.com/LearnBoost/node-canvas/blob/master/binding.gyp) + * [node-ffi](https://github.com/rbranson/node-ffi/blob/master/binding.gyp) + [libffi](https://github.com/rbranson/node-ffi/blob/master/deps/libffi/libffi.gyp) + * [node-time](https://github.com/TooTallNate/node-time/blob/master/binding.gyp) + * [node-sass](https://github.com/sass/node-sass/blob/master/binding.gyp) + [libsass](https://github.com/sass/node-sass/blob/master/src/libsass.gyp) + * [node-serialport](https://github.com/voodootikigod/node-serialport/blob/master/binding.gyp) + * [node-weak](https://github.com/TooTallNate/node-weak/blob/master/binding.gyp) + * [pty.js](https://github.com/chjj/pty.js/blob/master/binding.gyp) + * [ref](https://github.com/TooTallNate/ref/blob/master/binding.gyp) + * [appjs](https://github.com/milani/appjs/blob/master/binding.gyp) + * [nwm](https://github.com/mixu/nwm/blob/master/binding.gyp) + * [bcrypt](https://github.com/ncb000gt/node.bcrypt.js/blob/master/binding.gyp) + * [nk-mysql](https://github.com/mmod/nodamysql/blob/master/binding.gyp) + * [nk-xrm-installer](https://github.com/mmod/nk-xrm-installer/blob/master/binding.gyp) + [includable.gypi](https://github.com/mmod/nk-xrm-installer/blob/master/includable.gypi) + [unpack.py](https://github.com/mmod/nk-xrm-installer/blob/master/unpack.py) + [disburse.py](https://github.com/mmod/nk-xrm-installer/blob/master/disburse.py) + .py files above provide complete reference for examples of fetching source via http, extracting, and moving files. + * [node-memwatch](https://github.com/lloyd/node-memwatch/blob/master/binding.gyp) + * [node-ip2location](https://github.com/bolgovr/node-ip2location/blob/master/binding.gyp) + * [node-midi](https://github.com/justinlatimer/node-midi/blob/master/binding.gyp) + * [node-sqlite3](https://github.com/developmentseed/node-sqlite3/blob/master/binding.gyp) + [libsqlite3](https://github.com/developmentseed/node-sqlite3/blob/master/deps/sqlite3.gyp) + * [node-zipfile](https://github.com/mapbox/node-zipfile/blob/master/binding.gyp) + * [node-mapnik](https://github.com/mapnik/node-mapnik/blob/master/binding.gyp) + * [node-inotify](https://github.com/c4milo/node-inotify/blob/master/binding.gyp) + * [v8-profiler](https://github.com/c4milo/v8-profiler/blob/master/binding.gyp) + * [airtunes](https://github.com/radioline/node_airtunes/blob/master/binding.gyp) + * [node-fann](https://github.com/c4milo/node-fann/blob/master/binding.gyp) + * [node-talib](https://github.com/oransel/node-talib/blob/master/binding.gyp) + * [node-leveldown](https://github.com/rvagg/node-leveldown/blob/master/binding.gyp) + [leveldb.gyp](https://github.com/rvagg/node-leveldown/blob/master/deps/leveldb/leveldb.gyp) + [snappy.gyp](https://github.com/rvagg/node-leveldown/blob/master/deps/snappy/snappy.gyp) + * [node-expat](https://github.com/astro/node-expat/blob/master/binding.gyp) + [libexpat](https://github.com/astro/node-expat/blob/master/deps/libexpat/libexpat.gyp) + * [node-openvg-canvas](https://github.com/luismreis/node-openvg-canvas/blob/master/binding.gyp) + [node-openvg](https://github.com/luismreis/node-openvg/blob/master/binding.gyp) + * [node-cryptopp](https://github.com/BatikhSouri/node-cryptopp/blob/master/binding.gyp) + * [topcube](https://github.com/creationix/topcube/blob/master/binding.gyp) + * [node-osmium](https://github.com/osmcode/node-osmium/blob/master/binding.gyp) + * [node-osrm](https://github.com/DennisOSRM/node-osrm) + * [node-oracle](https://github.com/joeferner/node-oracle/blob/master/binding.gyp) + * [node-process-list](https://github.com/ReklatsMasters/node-process-list/blob/master/binding.gyp) + * [node-nanomsg](https://github.com/nickdesaulniers/node-nanomsg/blob/master/binding.gyp) + * [Ghostscript4JS](https://github.com/NickNaso/ghostscript4js/blob/master/binding.gyp) + * [nodecv](https://github.com/xudafeng/nodecv/blob/master/binding.gyp) + * [magick-cli](https://github.com/NickNaso/magick-cli/blob/master/binding.gyp) + * [sharp](https://github.com/lovell/sharp/blob/master/binding.gyp) + * [krb5](https://github.com/adaltas/node-krb5/blob/master/binding.gyp) + * [node-heapdump](https://github.com/bnoordhuis/node-heapdump/blob/master/binding.gyp) diff --git a/gyp/.github/workflows/Python_tests.yml b/gyp/.github/workflows/Python_tests.yml index 649251c8dd..aad135027c 100644 --- a/gyp/.github/workflows/Python_tests.yml +++ b/gyp/.github/workflows/Python_tests.yml @@ -2,7 +2,12 @@ # TODO: Enable pytest --doctest-modules name: Python_tests -on: [push, pull_request] +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: jobs: Python_tests: runs-on: ${{ matrix.os }} @@ -11,19 +16,20 @@ jobs: max-parallel: 8 matrix: os: [macos-latest, ubuntu-latest] # , windows-latest] - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11-dev"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install -r requirements_dev.txt + python -m pip install --upgrade pip setuptools + pip install --editable ".[dev]" + - run: ./gyp -V && ./gyp --version && gyp -V && gyp --version - name: Lint with flake8 - run: flake8 . --count --show-source --statistics + run: flake8 . --ignore=E203,W503 --max-complexity=101 --max-line-length=88 --show-source --statistics - name: Test with pytest run: pytest # - name: Run doctests with pytest diff --git a/gyp/.github/workflows/node-gyp.yml b/gyp/.github/workflows/node-gyp.yml index 78fe502bda..7cc1f9e075 100644 --- a/gyp/.github/workflows/node-gyp.yml +++ b/gyp/.github/workflows/node-gyp.yml @@ -1,30 +1,35 @@ name: node-gyp integration - -on: [push, pull_request] - +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: jobs: - test: + integration: strategy: fail-fast: false matrix: os: [macos-latest, ubuntu-latest, windows-latest] + python: ["3.7", "3.10"] + runs-on: ${{ matrix.os }} steps: - name: Clone gyp-next - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: path: gyp-next - name: Clone nodejs/node-gyp - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: nodejs/node-gyp path: node-gyp - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v3 with: node-version: 14.x - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: ${{ matrix.python }} - name: Install dependencies run: | cd node-gyp diff --git a/gyp/.github/workflows/nodejs-windows.yml b/gyp/.github/workflows/nodejs-windows.yml index fffe96e33b..4e6c9548ff 100644 --- a/gyp/.github/workflows/nodejs-windows.yml +++ b/gyp/.github/workflows/nodejs-windows.yml @@ -1,17 +1,22 @@ name: Node.js Windows integration -on: [push, pull_request] +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: jobs: build-windows: - runs-on: windows-latest + runs-on: windows-2019 steps: - name: Clone gyp-next - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: path: gyp-next - name: Clone nodejs/node - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: nodejs/node path: node diff --git a/gyp/.github/workflows/release-please.yml b/gyp/.github/workflows/release-please.yml index a414c10e15..665c4c48fe 100644 --- a/gyp/.github/workflows/release-please.yml +++ b/gyp/.github/workflows/release-please.yml @@ -1,16 +1,16 @@ on: push: branches: - - master + - main name: release-please jobs: release-please: runs-on: ubuntu-latest steps: - - uses: GoogleCloudPlatform/release-please-action@v2.5.6 + - uses: google-github-actions/release-please-action@v3 with: token: ${{ secrets.GITHUB_TOKEN }} release-type: python package-name: gyp-next - bump-minor-pre-major: Yes + bump-minor-pre-major: true diff --git a/gyp/CHANGELOG.md b/gyp/CHANGELOG.md index 52a07a29ac..4b4968f6a4 100644 --- a/gyp/CHANGELOG.md +++ b/gyp/CHANGELOG.md @@ -1,5 +1,133 @@ # Changelog +## [0.14.0](https://github.com/nodejs/gyp-next/compare/v0.13.0...v0.14.0) (2022-10-08) + + +### Features + +* Add command line argument for `gyp --version` ([#164](https://github.com/nodejs/gyp-next/issues/164)) ([5c9f4d0](https://github.com/nodejs/gyp-next/commit/5c9f4d05678dd855e18ed2327219e5d18e5374db)) +* ninja build for iOS ([#174](https://github.com/nodejs/gyp-next/issues/174)) ([b6f2714](https://github.com/nodejs/gyp-next/commit/b6f271424e0033d7ed54d437706695af2ba7a1bf)) +* **zos:** support IBM Open XL C/C++ & PL/I compilers on z/OS ([#178](https://github.com/nodejs/gyp-next/issues/178)) ([43a7211](https://github.com/nodejs/gyp-next/commit/43a72110ae3fafb13c9625cc7a969624b27cda47)) + + +### Bug Fixes + +* lock windows env ([#163](https://github.com/nodejs/gyp-next/issues/163)) ([44bd0dd](https://github.com/nodejs/gyp-next/commit/44bd0ddc93ea0b5770a44dd326a2e4ae62c21442)) +* move configuration information into pyproject.toml ([#176](https://github.com/nodejs/gyp-next/issues/176)) ([d69d8ec](https://github.com/nodejs/gyp-next/commit/d69d8ece6dbff7af4f2ea073c9fd170baf8cb7f7)) +* node.js debugger adds stderr (but exit code is 0) -> shouldn't throw ([#179](https://github.com/nodejs/gyp-next/issues/179)) ([1a457d9](https://github.com/nodejs/gyp-next/commit/1a457d9ed08cfd30c9fa551bc5cf0d90fb583787)) + +## [0.13.0](https://www.github.com/nodejs/gyp-next/compare/v0.12.1...v0.13.0) (2022-05-11) + + +### Features + +* add PRODUCT_DIR_ABS variable ([#151](https://www.github.com/nodejs/gyp-next/issues/151)) ([80d2626](https://www.github.com/nodejs/gyp-next/commit/80d26263581db829b61b312a7bdb5cc791df7824)) + + +### Bug Fixes + +* execvp: printf: Argument list too long ([#147](https://www.github.com/nodejs/gyp-next/issues/147)) ([c4e14f3](https://www.github.com/nodejs/gyp-next/commit/c4e14f301673fadbac3ab7882d0b5f4d02530cb9)) + +### [0.12.1](https://www.github.com/nodejs/gyp-next/compare/v0.12.0...v0.12.1) (2022-04-06) + + +### Bug Fixes + +* **msvs:** avoid fixing path for arguments with "=" ([#143](https://www.github.com/nodejs/gyp-next/issues/143)) ([7e8f16e](https://www.github.com/nodejs/gyp-next/commit/7e8f16eb165e042e64bec98fa6c2a0232a42c26b)) + +## [0.12.0](https://www.github.com/nodejs/gyp-next/compare/v0.11.0...v0.12.0) (2022-04-04) + + +### Features + +* support building shared libraries on z/OS ([#137](https://www.github.com/nodejs/gyp-next/issues/137)) ([293bcfa](https://www.github.com/nodejs/gyp-next/commit/293bcfa4c25c6adb743377adafc45a80fee492c6)) + +## [0.11.0](https://www.github.com/nodejs/gyp-next/compare/v0.10.1...v0.11.0) (2022-03-04) + + +### Features + +* Add proper support for IBM i ([#140](https://www.github.com/nodejs/gyp-next/issues/140)) ([fdda4a3](https://www.github.com/nodejs/gyp-next/commit/fdda4a3038b8a7042ad960ce7a223687c24a21b1)) + +### [0.10.1](https://www.github.com/nodejs/gyp-next/compare/v0.10.0...v0.10.1) (2021-11-24) + + +### Bug Fixes + +* **make:** only generate makefile for multiple toolsets if requested ([#133](https://www.github.com/nodejs/gyp-next/issues/133)) ([f463a77](https://www.github.com/nodejs/gyp-next/commit/f463a77705973289ea38fec1b244c922ac438e26)) + +## [0.10.0](https://www.github.com/nodejs/gyp-next/compare/v0.9.6...v0.10.0) (2021-08-26) + + +### Features + +* **msvs:** add support for Visual Studio 2022 ([#124](https://www.github.com/nodejs/gyp-next/issues/124)) ([4bd9215](https://www.github.com/nodejs/gyp-next/commit/4bd9215c44d300f06e916aec1d6327c22b78272d)) + +### [0.9.6](https://www.github.com/nodejs/gyp-next/compare/v0.9.5...v0.9.6) (2021-08-23) + + +### Bug Fixes + +* align flake8 test ([#122](https://www.github.com/nodejs/gyp-next/issues/122)) ([f1faa8d](https://www.github.com/nodejs/gyp-next/commit/f1faa8d3081e1a47e917ff910892f00dff16cf8a)) +* **msvs:** fix paths again in action command arguments ([#121](https://www.github.com/nodejs/gyp-next/issues/121)) ([7159dfb](https://www.github.com/nodejs/gyp-next/commit/7159dfbc5758c9ec717e215f2c36daf482c846a1)) + +### [0.9.5](https://www.github.com/nodejs/gyp-next/compare/v0.9.4...v0.9.5) (2021-08-18) + + +### Bug Fixes + +* add python 3.6 to node-gyp integration test ([3462d4c](https://www.github.com/nodejs/gyp-next/commit/3462d4ce3c31cce747513dc7ca9760c81d57c60e)) +* revert for windows compatibility ([d078e7d](https://www.github.com/nodejs/gyp-next/commit/d078e7d7ae080ddae243188f6415f940376a7368)) +* support msvs_quote_cmd in ninja generator ([#117](https://www.github.com/nodejs/gyp-next/issues/117)) ([46486ac](https://www.github.com/nodejs/gyp-next/commit/46486ac6e9329529d51061e006a5b39631e46729)) + +### [0.9.4](https://www.github.com/nodejs/gyp-next/compare/v0.9.3...v0.9.4) (2021-08-09) + + +### Bug Fixes + +* .S is an extension for asm file on Windows ([#115](https://www.github.com/nodejs/gyp-next/issues/115)) ([d2fad44](https://www.github.com/nodejs/gyp-next/commit/d2fad44ef3a79ca8900f1307060153ded57053fc)) + +### [0.9.3](https://www.github.com/nodejs/gyp-next/compare/v0.9.2...v0.9.3) (2021-07-07) + + +### Bug Fixes + +* build failure with ninja and Python 3 on Windows ([#113](https://www.github.com/nodejs/gyp-next/issues/113)) ([c172d10](https://www.github.com/nodejs/gyp-next/commit/c172d105deff5db4244e583942215918fa80dd3c)) + +### [0.9.2](https://www.github.com/nodejs/gyp-next/compare/v0.9.1...v0.9.2) (2021-05-21) + + +### Bug Fixes + +* add support of utf8 encoding ([#105](https://www.github.com/nodejs/gyp-next/issues/105)) ([4d0f93c](https://www.github.com/nodejs/gyp-next/commit/4d0f93c249286d1f0c0f665f5fe7346119f98cf1)) + +### [0.9.1](https://www.github.com/nodejs/gyp-next/compare/v0.9.0...v0.9.1) (2021-05-14) + + +### Bug Fixes + +* py lint ([3b6a8ee](https://www.github.com/nodejs/gyp-next/commit/3b6a8ee7a66193a8a6867eba9e1d2b70bdf04402)) + +## [0.9.0](https://www.github.com/nodejs/gyp-next/compare/v0.8.1...v0.9.0) (2021-05-13) + + +### Features + +* use LDFLAGS_host for host toolset ([#98](https://www.github.com/nodejs/gyp-next/issues/98)) ([bea5c7b](https://www.github.com/nodejs/gyp-next/commit/bea5c7bd67d6ad32acbdce79767a5481c70675a2)) + + +### Bug Fixes + +* msvs.py: remove overindentation ([#102](https://www.github.com/nodejs/gyp-next/issues/102)) ([3f83e99](https://www.github.com/nodejs/gyp-next/commit/3f83e99056d004d9579ceb786e06b624ddc36529)) +* update gyp.el to change case to cl-case ([#93](https://www.github.com/nodejs/gyp-next/issues/93)) ([13d5b66](https://www.github.com/nodejs/gyp-next/commit/13d5b66aab35985af9c2fb1174fdc6e1c1407ecc)) + +### [0.8.1](https://www.github.com/nodejs/gyp-next/compare/v0.8.0...v0.8.1) (2021-02-18) + + +### Bug Fixes + +* update shebang lines from python to python3 ([#94](https://www.github.com/nodejs/gyp-next/issues/94)) ([a1b0d41](https://www.github.com/nodejs/gyp-next/commit/a1b0d4171a8049a4ab7a614202063dec332f2df4)) + ## [0.8.0](https://www.github.com/nodejs/gyp-next/compare/v0.7.0...v0.8.0) (2021-01-15) diff --git a/gyp/CODE_OF_CONDUCT.md b/gyp/CODE_OF_CONDUCT.md index 4c21140559..d724027fd9 100644 --- a/gyp/CODE_OF_CONDUCT.md +++ b/gyp/CODE_OF_CONDUCT.md @@ -1,4 +1,4 @@ # Code of Conduct -* [Node.js Code of Conduct](https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md) -* [Node.js Moderation Policy](https://github.com/nodejs/admin/blob/master/Moderation-Policy.md) +* [Node.js Code of Conduct](https://github.com/nodejs/admin/blob/HEAD/CODE_OF_CONDUCT.md) +* [Node.js Moderation Policy](https://github.com/nodejs/admin/blob/HEAD/Moderation-Policy.md) diff --git a/gyp/CONTRIBUTING.md b/gyp/CONTRIBUTING.md index f9dd574a47..1a0bcde2b4 100644 --- a/gyp/CONTRIBUTING.md +++ b/gyp/CONTRIBUTING.md @@ -2,7 +2,7 @@ ## Code of Conduct -This project is bound to the [Node.js Code of Conduct](https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md). +This project is bound to the [Node.js Code of Conduct](https://github.com/nodejs/admin/blob/HEAD/CODE_OF_CONDUCT.md). ## Developer's Certificate of Origin 1.1 diff --git a/gyp/gyp_main.py b/gyp/gyp_main.py index f1559089d1..f23dcdf882 100755 --- a/gyp/gyp_main.py +++ b/gyp/gyp_main.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2009 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/gyp/pylib/gyp/MSVSSettings_test.py b/gyp/pylib/gyp/MSVSSettings_test.py index 7665c68e52..6ca09687ad 100755 --- a/gyp/pylib/gyp/MSVSSettings_test.py +++ b/gyp/pylib/gyp/MSVSSettings_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/gyp/pylib/gyp/MSVSUtil.py b/gyp/pylib/gyp/MSVSUtil.py index cb55305eae..36bb782bd3 100644 --- a/gyp/pylib/gyp/MSVSUtil.py +++ b/gyp/pylib/gyp/MSVSUtil.py @@ -55,7 +55,7 @@ def _SuffixName(name, suffix): Target name with suffix added (foo_suffix#target) """ parts = name.rsplit("#", 1) - parts[0] = "{}_{}".format(parts[0], suffix) + parts[0] = f"{parts[0]}_{suffix}" return "#".join(parts) diff --git a/gyp/pylib/gyp/MSVSVersion.py b/gyp/pylib/gyp/MSVSVersion.py index 134b35557b..8d7f21e82d 100644 --- a/gyp/pylib/gyp/MSVSVersion.py +++ b/gyp/pylib/gyp/MSVSVersion.py @@ -269,6 +269,18 @@ def _CreateVersion(name, path, sdk_based=False): if path: path = os.path.normpath(path) versions = { + "2022": VisualStudioVersion( + "2022", + "Visual Studio 2022", + solution_version="12.00", + project_version="17.0", + flat_sln=False, + uses_vcxproj=True, + path=path, + sdk_based=sdk_based, + default_toolset="v143", + compatible_sdks=["v8.1", "v10.0"], + ), "2019": VisualStudioVersion( "2019", "Visual Studio 2019", @@ -436,6 +448,7 @@ def _DetectVisualStudioVersions(versions_to_check, force_express): 2015 - Visual Studio 2015 (14) 2017 - Visual Studio 2017 (15) 2019 - Visual Studio 2019 (16) + 2022 - Visual Studio 2022 (17) Where (e) is e for express editions of MSVS and blank otherwise. """ version_to_year = { @@ -447,6 +460,7 @@ def _DetectVisualStudioVersions(versions_to_check, force_express): "14.0": "2015", "15.0": "2017", "16.0": "2019", + "17.0": "2022", } versions = [] for version in versions_to_check: @@ -522,7 +536,7 @@ def SelectVisualStudioVersion(version="auto", allow_fallback=True): if version == "auto": version = os.environ.get("GYP_MSVS_VERSION", "auto") version_map = { - "auto": ("16.0", "15.0", "14.0", "12.0", "10.0", "9.0", "8.0", "11.0"), + "auto": ("17.0", "16.0", "15.0", "14.0", "12.0", "10.0", "9.0", "8.0", "11.0"), "2005": ("8.0",), "2005e": ("8.0",), "2008": ("9.0",), @@ -536,6 +550,7 @@ def SelectVisualStudioVersion(version="auto", allow_fallback=True): "2015": ("14.0",), "2017": ("15.0",), "2019": ("16.0",), + "2022": ("17.0",), } override_path = os.environ.get("GYP_MSVS_OVERRIDE_PATH") if override_path: diff --git a/gyp/pylib/gyp/__init__.py b/gyp/pylib/gyp/__init__.py index 52549fff11..2aa39d0318 100755 --- a/gyp/pylib/gyp/__init__.py +++ b/gyp/pylib/gyp/__init__.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be @@ -15,6 +15,7 @@ import traceback from gyp.common import GypError + # Default debug modes for GYP debug = {} @@ -103,6 +104,18 @@ def Load( for (key, val) in generator.generator_default_variables.items(): default_variables.setdefault(key, val) + output_dir = params["options"].generator_output or params["options"].toplevel_dir + if default_variables["GENERATOR"] == "ninja": + default_variables.setdefault( + "PRODUCT_DIR_ABS", + os.path.join(output_dir, "out", default_variables["build_type"]), + ) + else: + default_variables.setdefault( + "PRODUCT_DIR_ABS", + os.path.join(output_dir, default_variables["CONFIGURATION_NAME"]), + ) + # Give the generator the opportunity to set additional variables based on # the params it will receive in the output phase. if getattr(generator, "CalculateVariables", None): @@ -451,8 +464,19 @@ def gyp_main(args): metavar="TARGET", help="include only TARGET and its deep dependencies", ) + parser.add_argument( + "-V", + "--version", + dest="version", + action="store_true", + help="Show the version and exit.", + ) options, build_files_arg = parser.parse_args(args) + if options.version: + import pkg_resources + print(f"v{pkg_resources.get_distribution('gyp-next').version}") + return 0 build_files = build_files_arg # Set up the configuration directory (defaults to ~/.gyp) diff --git a/gyp/pylib/gyp/common.py b/gyp/pylib/gyp/common.py index ba310ce247..d77adee8af 100644 --- a/gyp/pylib/gyp/common.py +++ b/gyp/pylib/gyp/common.py @@ -454,6 +454,8 @@ def GetFlavor(params): return "aix" if sys.platform.startswith(("os390", "zos")): return "zos" + if sys.platform == "os400": + return "os400" return "linux" @@ -463,9 +465,14 @@ def CopyTool(flavor, out_path, generator_flags={}): to |out_path|.""" # aix and solaris just need flock emulation. mac and win use more complicated # support scripts. - prefix = {"aix": "flock", "solaris": "flock", "mac": "mac", "win": "win"}.get( - flavor, None - ) + prefix = { + "aix": "flock", + "os400": "flock", + "solaris": "flock", + "mac": "mac", + "ios": "mac", + "win": "win", + }.get(flavor, None) if not prefix: return @@ -562,7 +569,7 @@ def pop(self, last=True): # pylint: disable=W0221 def __repr__(self): if not self: return f"{self.__class__.__name__}()" - return "{}({!r})".format(self.__class__.__name__, list(self)) + return f"{self.__class__.__name__}({list(self)!r})" def __eq__(self, other): if isinstance(other, OrderedSet): diff --git a/gyp/pylib/gyp/common_test.py b/gyp/pylib/gyp/common_test.py index 0310fb266c..05344085ad 100755 --- a/gyp/pylib/gyp/common_test.py +++ b/gyp/pylib/gyp/common_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/gyp/pylib/gyp/easy_xml.py b/gyp/pylib/gyp/easy_xml.py index e475b5530c..bda1a47468 100644 --- a/gyp/pylib/gyp/easy_xml.py +++ b/gyp/pylib/gyp/easy_xml.py @@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import sys import re import os import locale @@ -84,7 +85,7 @@ def _ConstructContentList(xml_parts, specification, pretty, level=0): rest = specification[1:] if rest and isinstance(rest[0], dict): for at, val in sorted(rest[0].items()): - xml_parts.append(' {}="{}"'.format(at, _XmlEscape(val, attr=True))) + xml_parts.append(f' {at}="{_XmlEscape(val, attr=True)}"') rest = rest[1:] if rest: xml_parts.append(">") @@ -106,7 +107,8 @@ def _ConstructContentList(xml_parts, specification, pretty, level=0): xml_parts.append("/>%s" % new_line) -def WriteXmlIfChanged(content, path, encoding="utf-8", pretty=False, win32=False): +def WriteXmlIfChanged(content, path, encoding="utf-8", pretty=False, + win32=(sys.platform == "win32")): """ Writes the XML content to disk, touching the file only if it has changed. Args: diff --git a/gyp/pylib/gyp/easy_xml_test.py b/gyp/pylib/gyp/easy_xml_test.py index c21e054246..342f693a32 100755 --- a/gyp/pylib/gyp/easy_xml_test.py +++ b/gyp/pylib/gyp/easy_xml_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2011 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/gyp/pylib/gyp/flock_tool.py b/gyp/pylib/gyp/flock_tool.py index c649a89ef8..0754aff26f 100755 --- a/gyp/pylib/gyp/flock_tool.py +++ b/gyp/pylib/gyp/flock_tool.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2011 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -41,7 +41,7 @@ def ExecFlock(self, lockfile, *cmd_list): # with EBADF, that's why we use this F_SETLK # hack instead. fd = os.open(lockfile, os.O_WRONLY | os.O_NOCTTY | os.O_CREAT, 0o666) - if sys.platform.startswith("aix"): + if sys.platform.startswith("aix") or sys.platform == "os400": # Python on AIX is compiled with LARGEFILE support, which changes the # struct size. op = struct.pack("hhIllqq", fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0) diff --git a/gyp/pylib/gyp/generator/android.py b/gyp/pylib/gyp/generator/android.py index 040d8088a2..cdf1a4832c 100644 --- a/gyp/pylib/gyp/generator/android.py +++ b/gyp/pylib/gyp/generator/android.py @@ -349,7 +349,7 @@ def WriteActions(self, actions, extra_sources, extra_outputs): for output in outputs[1:]: # Make each output depend on the main output, with an empty command # to force make to notice that the mtime has changed. - self.WriteLn("{}: {} ;".format(self.LocalPathify(output), main_output)) + self.WriteLn(f"{self.LocalPathify(output)}: {main_output} ;") extra_outputs += outputs self.WriteLn() @@ -616,7 +616,7 @@ def WriteSources(self, spec, configs, extra_sources): if IsCPPExtension(ext) and ext != local_cpp_extension: local_file = root + local_cpp_extension if local_file != source: - self.WriteLn("{}: {}".format(local_file, self.LocalPathify(source))) + self.WriteLn(f"{local_file}: {self.LocalPathify(source)}") self.WriteLn("\tmkdir -p $(@D); cp $< $@") origin_src_dirs.append(os.path.dirname(source)) final_generated_sources.append(local_file) @@ -908,7 +908,7 @@ def WriteTarget( if isinstance(v, list): self.WriteList(v, k) else: - self.WriteLn("{} := {}".format(k, make.QuoteIfNecessary(v))) + self.WriteLn(f"{k} := {make.QuoteIfNecessary(v)}") self.WriteLn("") # Add to the set of targets which represent the gyp 'all' target. We use the diff --git a/gyp/pylib/gyp/generator/eclipse.py b/gyp/pylib/gyp/generator/eclipse.py index 1ff0dc83ae..a851b4db75 100644 --- a/gyp/pylib/gyp/generator/eclipse.py +++ b/gyp/pylib/gyp/generator/eclipse.py @@ -24,7 +24,7 @@ import gyp.common import gyp.msvs_emulation import shlex -import xml.etree.cElementTree as ET +import xml.etree.ElementTree as ET generator_wants_static_library_dependencies_adjusted = False diff --git a/gyp/pylib/gyp/generator/make.py b/gyp/pylib/gyp/generator/make.py index 857875a564..05bb609d16 100644 --- a/gyp/pylib/gyp/generator/make.py +++ b/gyp/pylib/gyp/generator/make.py @@ -50,7 +50,7 @@ } # Make supports multiple toolsets -generator_supports_multiple_toolsets = True +generator_supports_multiple_toolsets = gyp.common.CrossCompileRequested() # Request sorted dependencies in the order from dependents to dependencies. generator_wants_sorted_dependencies = False @@ -99,6 +99,9 @@ def CalculateVariables(default_variables, params): default_variables.setdefault("OS", operating_system) if flavor == "aix": default_variables.setdefault("SHARED_LIB_SUFFIX", ".a") + elif flavor == "zos": + default_variables.setdefault("SHARED_LIB_SUFFIX", ".x") + COMPILABLE_EXTENSIONS.update({".pli": "pli"}) else: default_variables.setdefault("SHARED_LIB_SUFFIX", ".so") default_variables.setdefault("SHARED_LIB_DIR", "$(builddir)/lib.$(TOOLSET)") @@ -154,6 +157,31 @@ def CalculateGeneratorInputInfo(params): quiet_cmd_link = LINK($(TOOLSET)) $@ cmd_link = $(LINK.$(TOOLSET)) -o $@ $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,--start-group $(LD_INPUTS) $(LIBS) -Wl,--end-group +# Note: this does not handle spaces in paths +define xargs + $(1) $(word 1,$(2)) +$(if $(word 2,$(2)),$(call xargs,$(1),$(wordlist 2,$(words $(2)),$(2)))) +endef + +define write-to-file + @: >$(1) +$(call xargs,@printf "%s\\n" >>$(1),$(2)) +endef + +OBJ_FILE_LIST := ar-file-list + +define create_archive + rm -f $(1) $(1).$(OBJ_FILE_LIST); mkdir -p `dirname $(1)` + $(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2))) + $(AR.$(TOOLSET)) crs $(1) @$(1).$(OBJ_FILE_LIST) +endef + +define create_thin_archive + rm -f $(1) $(OBJ_FILE_LIST); mkdir -p `dirname $(1)` + $(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2))) + $(AR.$(TOOLSET)) crsT $(1) @$(1).$(OBJ_FILE_LIST) +endef + # We support two kinds of shared objects (.so): # 1) shared_library, which is just bundling together many dependent libraries # into a link line. @@ -198,6 +226,31 @@ def CalculateGeneratorInputInfo(params): quiet_cmd_alink_thin = AR($(TOOLSET)) $@ cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^) +# Note: this does not handle spaces in paths +define xargs + $(1) $(word 1,$(2)) +$(if $(word 2,$(2)),$(call xargs,$(1),$(wordlist 2,$(words $(2)),$(2)))) +endef + +define write-to-file + @: >$(1) +$(call xargs,@printf "%s\\n" >>$(1),$(2)) +endef + +OBJ_FILE_LIST := ar-file-list + +define create_archive + rm -f $(1) $(1).$(OBJ_FILE_LIST); mkdir -p `dirname $(1)` + $(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2))) + $(AR.$(TOOLSET)) crs $(1) @$(1).$(OBJ_FILE_LIST) +endef + +define create_thin_archive + rm -f $(1) $(OBJ_FILE_LIST); mkdir -p `dirname $(1)` + $(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2))) + $(AR.$(TOOLSET)) crsT $(1) @$(1).$(OBJ_FILE_LIST) +endef + # Due to circular dependencies between libraries :(, we wrap the # special "figure out circular dependencies" flags around the entire # input list during linking. @@ -237,6 +290,24 @@ def CalculateGeneratorInputInfo(params): """ # noqa: E501 +LINK_COMMANDS_OS400 = """\ +quiet_cmd_alink = AR($(TOOLSET)) $@ +cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) -X64 crs $@ $(filter %.o,$^) + +quiet_cmd_alink_thin = AR($(TOOLSET)) $@ +cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) -X64 crs $@ $(filter %.o,$^) + +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) +""" # noqa: E501 + + LINK_COMMANDS_OS390 = """\ quiet_cmd_alink = AR($(TOOLSET)) $@ cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) @@ -248,10 +319,10 @@ def CalculateGeneratorInputInfo(params): cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) quiet_cmd_solink = SOLINK($(TOOLSET)) $@ -cmd_solink = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) -Wl,DLL +cmd_solink = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ -cmd_solink_module = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) -Wl,DLL +cmd_solink_module = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) """ # noqa: E501 @@ -308,6 +379,7 @@ def CalculateGeneratorInputInfo(params): LINK.target ?= %(LINK.target)s LDFLAGS.target ?= $(LDFLAGS) AR.target ?= $(AR) +PLI.target ?= %(PLI.target)s # C++ apps need to be linked with g++. LINK ?= $(CXX.target) @@ -319,8 +391,9 @@ def CalculateGeneratorInputInfo(params): CXX.host ?= %(CXX.host)s CXXFLAGS.host ?= $(CPPFLAGS_host) $(CXXFLAGS_host) LINK.host ?= %(LINK.host)s -LDFLAGS.host ?= +LDFLAGS.host ?= $(LDFLAGS_host) AR.host ?= %(AR.host)s +PLI.host ?= %(PLI.host)s # Define a dir function that can handle spaces. # http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions @@ -400,6 +473,9 @@ def CalculateGeneratorInputInfo(params): # send stderr to /dev/null to ignore messages when linking directories. cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp %(copy_archive_args)s "$<" "$@") +quiet_cmd_symlink = SYMLINK $@ +cmd_symlink = ln -sf "$<" "$@" + %(link_commands)s """ # noqa: E501 r""" @@ -555,6 +631,15 @@ def WriteRootHeaderSuffixRules(writer): writer.write("\n") +SHARED_HEADER_OS390_COMMANDS = """ +PLIFLAGS.target ?= -qlp=64 -qlimits=extname=31 $(PLIFLAGS) +PLIFLAGS.host ?= -qlp=64 -qlimits=extname=31 $(PLIFLAGS) + +quiet_cmd_pli = PLI($(TOOLSET)) $@ +cmd_pli = $(PLI.$(TOOLSET)) $(GYP_PLIFLAGS) $(PLIFLAGS.$(TOOLSET)) -c $< && \ + if [ -f $(notdir $@) ]; then /bin/cp $(notdir $@) $@; else true; fi +""" + SHARED_HEADER_SUFFIX_RULES_COMMENT1 = """\ # Suffix rules, putting all outputs into $(obj). """ @@ -981,12 +1066,20 @@ def WriteActions( # libraries, but until everything is made cross-compile safe, also use # target libraries. # TODO(piman): when everything is cross-compile safe, remove lib.target - self.WriteLn( - "cmd_%s = LD_LIBRARY_PATH=$(builddir)/lib.host:" - "$(builddir)/lib.target:$$LD_LIBRARY_PATH; " - "export LD_LIBRARY_PATH; " - "%s%s" % (name, cd_action, command) - ) + if self.flavor == "zos" or self.flavor == "aix": + self.WriteLn( + "cmd_%s = LIBPATH=$(builddir)/lib.host:" + "$(builddir)/lib.target:$$LIBPATH; " + "export LIBPATH; " + "%s%s" % (name, cd_action, command) + ) + else: + self.WriteLn( + "cmd_%s = LD_LIBRARY_PATH=$(builddir)/lib.host:" + "$(builddir)/lib.target:$$LD_LIBRARY_PATH; " + "export LD_LIBRARY_PATH; " + "%s%s" % (name, cd_action, command) + ) self.WriteLn() outputs = [self.Absolutify(o) for o in outputs] # The makefile rules are all relative to the top dir, but the gyp actions @@ -1480,6 +1573,8 @@ def ComputeOutputBasename(self, spec): target_prefix = "lib" if self.flavor == "aix": target_ext = ".a" + elif self.flavor == "zos": + target_ext = ".x" else: target_ext = ".so" elif self.type == "none": @@ -1560,6 +1655,14 @@ def ComputeDeps(self, spec): # link_deps.extend(spec.get('libraries', [])) return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps)) + def GetSharedObjectFromSidedeck(self, sidedeck): + """Return the shared object files based on sidedeck""" + return re.sub(r"\.x$", ".so", sidedeck) + + def GetUnversionedSidedeckFromSidedeck(self, sidedeck): + """Return the shared object files based on sidedeck""" + return re.sub(r"\.\d+\.x$", ".x", sidedeck) + def WriteDependencyOnExtraOutputs(self, target, extra_outputs): self.WriteMakeRule( [self.output_binary], @@ -1768,21 +1871,35 @@ def WriteTarget( self.flavor not in ("mac", "openbsd", "netbsd", "win") and not self.is_standalone_static_library ): - self.WriteDoCmd( - [self.output_binary], - link_deps, - "alink_thin", - part_of_all, - postbuilds=postbuilds, - ) + if self.flavor in ("linux", "android"): + self.WriteMakeRule( + [self.output_binary], + link_deps, + actions=["$(call create_thin_archive,$@,$^)"], + ) + else: + self.WriteDoCmd( + [self.output_binary], + link_deps, + "alink_thin", + part_of_all, + postbuilds=postbuilds, + ) else: - self.WriteDoCmd( - [self.output_binary], - link_deps, - "alink", - part_of_all, - postbuilds=postbuilds, - ) + if self.flavor in ("linux", "android"): + self.WriteMakeRule( + [self.output_binary], + link_deps, + actions=["$(call create_archive,$@,$^)"], + ) + else: + self.WriteDoCmd( + [self.output_binary], + link_deps, + "alink", + part_of_all, + postbuilds=postbuilds, + ) elif self.type == "shared_library": self.WriteLn( "%s: LD_INPUTS := %s" @@ -1798,6 +1915,17 @@ def WriteTarget( part_of_all, postbuilds=postbuilds, ) + # z/OS has a .so target as well as a sidedeck .x target + if self.flavor == "zos": + self.WriteLn( + "%s: %s" + % ( + QuoteSpaces( + self.GetSharedObjectFromSidedeck(self.output_binary) + ), + QuoteSpaces(self.output_binary), + ) + ) elif self.type == "loadable_module": for link_dep in link_deps: assert " " not in link_dep, ( @@ -1855,17 +1983,16 @@ def WriteTarget( else: file_desc = "executable" install_path = self._InstallableTargetInstallPath() - installable_deps = [self.output] + installable_deps = [] + if self.flavor != "zos": + installable_deps.append(self.output) if ( self.flavor == "mac" and "product_dir" not in spec and self.toolset == "target" ): - # On mac, products are created in install_path immediately. - assert install_path == self.output, "{} != {}".format( - install_path, - self.output, - ) + # On macOS, products are created in install_path immediately. + assert install_path == self.output, f"{install_path} != {self.output}" # Point the target alias to the final binary output. self.WriteMakeRule( @@ -1880,7 +2007,30 @@ def WriteTarget( comment="Copy this to the %s output path." % file_desc, part_of_all=part_of_all, ) - installable_deps.append(install_path) + if self.flavor != "zos": + installable_deps.append(install_path) + if self.flavor == "zos" and self.type == "shared_library": + # lib.target/libnode.so has a dependency on $(obj).target/libnode.so + self.WriteDoCmd( + [self.GetSharedObjectFromSidedeck(install_path)], + [self.GetSharedObjectFromSidedeck(self.output)], + "copy", + comment="Copy this to the %s output path." % file_desc, + part_of_all=part_of_all, + ) + # Create a symlink of libnode.x to libnode.version.x + self.WriteDoCmd( + [self.GetUnversionedSidedeckFromSidedeck(install_path)], + [install_path], + "symlink", + comment="Symlnk this to the %s output path." % file_desc, + part_of_all=part_of_all, + ) + # Place libnode.version.so and libnode.x symlink in lib.target dir + installable_deps.append(self.GetSharedObjectFromSidedeck(install_path)) + installable_deps.append( + self.GetUnversionedSidedeckFromSidedeck(install_path) + ) if self.output != self.alias and self.alias != self.target: self.WriteMakeRule( [self.alias], @@ -1888,7 +2038,18 @@ def WriteTarget( comment="Short alias for building this %s." % file_desc, phony=True, ) - if part_of_all: + if self.flavor == "zos" and self.type == "shared_library": + # Make sure that .x symlink target is run + self.WriteMakeRule( + ["all"], + [ + self.GetUnversionedSidedeckFromSidedeck(install_path), + self.GetSharedObjectFromSidedeck(install_path), + ], + comment='Add %s to "all" target.' % file_desc, + phony=True, + ) + elif part_of_all: self.WriteMakeRule( ["all"], [install_path], @@ -2133,7 +2294,7 @@ def WriteSortedXcodeEnv(self, target, env): # export foo := a\ b # it does not -- the backslash is written to the env as literal character. # So don't escape spaces in |env[k]|. - self.WriteLn("{}: export {} := {}".format(QuoteSpaces(target), k, v)) + self.WriteLn(f"{QuoteSpaces(target)}: export {k} := {v}") def Objectify(self, path): """Convert a path to its output directory form.""" @@ -2184,6 +2345,9 @@ def _InstallableTargetInstallPath(self): # # Install all shared libs into a common directory (per toolset) for # # convenient access with LD_LIBRARY_PATH. # return "$(builddir)/lib.%s/%s" % (self.toolset, self.alias) + if self.flavor == "zos" and self.type == "shared_library": + return "$(builddir)/lib.%s/%s" % (self.toolset, self.alias) + return "$(builddir)/" + self.alias @@ -2295,10 +2459,12 @@ def CalculateMakefilePath(build_file, base_name): "AR.target": GetEnvironFallback(("AR_target", "AR"), "$(AR)"), "CXX.target": GetEnvironFallback(("CXX_target", "CXX"), "$(CXX)"), "LINK.target": GetEnvironFallback(("LINK_target", "LINK"), "$(LINK)"), + "PLI.target": GetEnvironFallback(("PLI_target", "PLI"), "pli"), "CC.host": GetEnvironFallback(("CC_host", "CC"), "gcc"), "AR.host": GetEnvironFallback(("AR_host", "AR"), "ar"), "CXX.host": GetEnvironFallback(("CXX_host", "CXX"), "g++"), "LINK.host": GetEnvironFallback(("LINK_host", "LINK"), "$(CXX.host)"), + "PLI.host": GetEnvironFallback(("PLI_host", "PLI"), "pli"), } if flavor == "mac": flock_command = "./gyp-mac-tool flock" @@ -2314,16 +2480,36 @@ def CalculateMakefilePath(build_file, base_name): header_params.update({"link_commands": LINK_COMMANDS_ANDROID}) elif flavor == "zos": copy_archive_arguments = "-fPR" - makedep_arguments = "-qmakedep=gcc" + CC_target = GetEnvironFallback(("CC_target", "CC"), "njsc") + makedep_arguments = "-MMD" + if CC_target == "clang": + CC_host = GetEnvironFallback(("CC_host", "CC"), "clang") + CXX_target = GetEnvironFallback(("CXX_target", "CXX"), "clang++") + CXX_host = GetEnvironFallback(("CXX_host", "CXX"), "clang++") + elif CC_target == "ibm-clang64": + CC_host = GetEnvironFallback(("CC_host", "CC"), "ibm-clang64") + CXX_target = GetEnvironFallback(("CXX_target", "CXX"), "ibm-clang++64") + CXX_host = GetEnvironFallback(("CXX_host", "CXX"), "ibm-clang++64") + elif CC_target == "ibm-clang": + CC_host = GetEnvironFallback(("CC_host", "CC"), "ibm-clang") + CXX_target = GetEnvironFallback(("CXX_target", "CXX"), "ibm-clang++") + CXX_host = GetEnvironFallback(("CXX_host", "CXX"), "ibm-clang++") + else: + # Node.js versions prior to v18: + makedep_arguments = "-qmakedep=gcc" + CC_host = GetEnvironFallback(("CC_host", "CC"), "njsc") + CXX_target = GetEnvironFallback(("CXX_target", "CXX"), "njsc++") + CXX_host = GetEnvironFallback(("CXX_host", "CXX"), "njsc++") header_params.update( { "copy_archive_args": copy_archive_arguments, "makedep_args": makedep_arguments, "link_commands": LINK_COMMANDS_OS390, - "CC.target": GetEnvironFallback(("CC_target", "CC"), "njsc"), - "CXX.target": GetEnvironFallback(("CXX_target", "CXX"), "njsc++"), - "CC.host": GetEnvironFallback(("CC_host", "CC"), "njsc"), - "CXX.host": GetEnvironFallback(("CXX_host", "CXX"), "njsc++"), + "extra_commands": SHARED_HEADER_OS390_COMMANDS, + "CC.target": CC_target, + "CXX.target": CXX_target, + "CC.host": CC_host, + "CXX.host": CXX_host, } ) elif flavor == "solaris": @@ -2351,6 +2537,16 @@ def CalculateMakefilePath(build_file, base_name): "flock_index": 2, } ) + elif flavor == "os400": + copy_archive_arguments = "-pPRf" + header_params.update( + { + "copy_archive_args": copy_archive_arguments, + "link_commands": LINK_COMMANDS_OS400, + "flock": "./gyp-flock-tool flock", + "flock_index": 2, + } + ) build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) make_global_settings_array = data[build_file].get("make_global_settings", []) diff --git a/gyp/pylib/gyp/generator/msvs.py b/gyp/pylib/gyp/generator/msvs.py index e5f9dbb542..fd95005784 100644 --- a/gyp/pylib/gyp/generator/msvs.py +++ b/gyp/pylib/gyp/generator/msvs.py @@ -152,7 +152,7 @@ def _NormalizedSource(source): return source -def _FixPath(path): +def _FixPath(path, separator="\\"): """Convert paths to a form that will make sense in a vcproj file. Arguments: @@ -168,9 +168,12 @@ def _FixPath(path): and not _IsWindowsAbsPath(path) ): path = os.path.join(fixpath_prefix, path) - path = path.replace("/", "\\") + if separator == "\\": + path = path.replace("/", "\\") path = _NormalizedSource(path) - if path and path[-1] == "\\": + if separator == "/": + path = path.replace("\\", "/") + if path and path[-1] == separator: path = path[:-1] return path @@ -185,9 +188,9 @@ def _IsWindowsAbsPath(path): return path.startswith("c:") or path.startswith("C:") -def _FixPaths(paths): +def _FixPaths(paths, separator="\\"): """Fix each of the paths of the list.""" - return [_FixPath(i) for i in paths] + return [_FixPath(i, separator) for i in paths] def _ConvertSourcesToFilterHierarchy( @@ -314,7 +317,7 @@ def _ConfigBaseName(config_name, platform_name): def _ConfigFullName(config_name, config_data): platform_name = _ConfigPlatform(config_data) - return "{}|{}".format(_ConfigBaseName(config_name, platform_name), platform_name) + return f"{_ConfigBaseName(config_name, platform_name)}|{platform_name}" def _ConfigWindowsTargetPlatformVersion(config_data, version): @@ -335,7 +338,7 @@ def _ConfigWindowsTargetPlatformVersion(config_data, version): # Find a matching entry in sdk_dir\include. expected_sdk_dir = r"%s\include" % sdk_dir names = sorted( - [ + ( x for x in ( os.listdir(expected_sdk_dir) @@ -343,7 +346,7 @@ def _ConfigWindowsTargetPlatformVersion(config_data, version): else [] ) if x.startswith(version) - ], + ), reverse=True, ) if names: @@ -418,7 +421,18 @@ def _BuildCommandLineForRuleRaw( # file out of the raw command string, and some commands (like python) are # actually batch files themselves. command.insert(0, "call") - arguments = [i.replace("$(InputDir)", "%INPUTDIR%") for i in cmd[1:]] + # Fix the paths + # TODO(quote): This is a really ugly heuristic, and will miss path fixing + # for arguments like "--arg=path", arg=path, or "/opt:path". + # If the argument starts with a slash or dash, or contains an equal sign, + # it's probably a command line switch. + # Return the path with forward slashes because the command using it might + # not support backslashes. + arguments = [ + i if (i[:1] in "/-" or "=" in i) else _FixPath(i, "/") + for i in cmd[1:] + ] + arguments = [i.replace("$(InputDir)", "%INPUTDIR%") for i in arguments] arguments = [MSVSSettings.FixVCMacroSlashes(i) for i in arguments] if quote_cmd: # Support a mode for using cmd directly. @@ -3276,9 +3290,9 @@ def GetEdges(node): # append to the default value. I.e. PATH=$(PATH);other_path edges.update( { - v - for v in MSVS_VARIABLE_REFERENCE.findall(value) - if v in properties and v != node + v + for v in MSVS_VARIABLE_REFERENCE.findall(value) + if v in properties and v != node } ) return edges diff --git a/gyp/pylib/gyp/generator/msvs_test.py b/gyp/pylib/gyp/generator/msvs_test.py index 69a5c7ec0e..e80b57f06a 100755 --- a/gyp/pylib/gyp/generator/msvs_test.py +++ b/gyp/pylib/gyp/generator/msvs_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/gyp/pylib/gyp/generator/ninja.py b/gyp/pylib/gyp/generator/ninja.py index c57bec6abb..ca04ee13a1 100644 --- a/gyp/pylib/gyp/generator/ninja.py +++ b/gyp/pylib/gyp/generator/ninja.py @@ -638,7 +638,7 @@ def GenerateDescription(self, verb, message, fallback): if self.toolset != "target": verb += "(%s)" % self.toolset if message: - return "{} {}".format(verb, self.ExpandSpecial(message)) + return f"{verb} {self.ExpandSpecial(message)}" else: return f"{verb} {self.name}: {fallback}" @@ -654,10 +654,10 @@ def WriteActions( description = self.GenerateDescription( "ACTION", action.get("message", None), name ) - is_cygwin = ( - self.msvs_settings.IsRuleRunUnderCygwin(action) + win_shell_flags = ( + self.msvs_settings.GetRuleShellFlags(action) if self.flavor == "win" - else False + else None ) args = action["action"] depfile = action.get("depfile", None) @@ -665,7 +665,7 @@ def WriteActions( depfile = self.ExpandSpecial(depfile, self.base_to_build) pool = "console" if int(action.get("ninja_use_console", 0)) else None rule_name, _ = self.WriteNewNinjaRule( - name, args, description, is_cygwin, env, pool, depfile=depfile + name, args, description, win_shell_flags, env, pool, depfile=depfile ) inputs = [self.GypPathToNinja(i, env) for i in action["inputs"]] @@ -707,14 +707,14 @@ def WriteRules( rule.get("message", None), ("%s " + generator_default_variables["RULE_INPUT_PATH"]) % name, ) - is_cygwin = ( - self.msvs_settings.IsRuleRunUnderCygwin(rule) + win_shell_flags = ( + self.msvs_settings.GetRuleShellFlags(rule) if self.flavor == "win" - else False + else None ) pool = "console" if int(rule.get("ninja_use_console", 0)) else None rule_name, args = self.WriteNewNinjaRule( - name, args, description, is_cygwin, env, pool + name, args, description, win_shell_flags, env, pool ) # TODO: if the command references the outputs directly, we should @@ -733,7 +733,7 @@ def WriteRules( def cygwin_munge(path): # pylint: disable=cell-var-from-loop - if is_cygwin: + if win_shell_flags and win_shell_flags.cygwin: return path.replace("\\", "/") return path @@ -1221,7 +1221,7 @@ def WriteSourcesForArch( command = "cc_s" elif ( self.flavor == "win" - and ext == "asm" + and ext in ("asm", "S") and not self.msvs_settings.HasExplicitAsmRules(spec) ): command = "asm" @@ -1417,7 +1417,11 @@ def WriteLinkForArch( is_executable = spec["type"] == "executable" # The ldflags config key is not used on mac or win. On those platforms # linker flags are set via xcode_settings and msvs_settings, respectively. - env_ldflags = os.environ.get("LDFLAGS", "").split() + if self.toolset == "target": + env_ldflags = os.environ.get("LDFLAGS", "").split() + elif self.toolset == "host": + env_ldflags = os.environ.get("LDFLAGS_host", "").split() + if self.flavor == "mac": ldflags = self.xcode_settings.GetLdflags( config_name, @@ -1579,7 +1583,7 @@ def WriteTarget(self, spec, config_name, config, link_deps, compile_deps): elif spec["type"] == "static_library": self.target.binary = self.ComputeOutput(spec) if ( - self.flavor not in ("mac", "openbsd", "netbsd", "win") + self.flavor not in ("ios", "mac", "netbsd", "openbsd", "win") and not self.is_standalone_static_library ): self.ninja.build( @@ -1895,7 +1899,7 @@ def WriteVariableList(self, ninja_file, var, values): ninja_file.variable(var, " ".join(values)) def WriteNewNinjaRule( - self, name, args, description, is_cygwin, env, pool, depfile=None + self, name, args, description, win_shell_flags, env, pool, depfile=None ): """Write out a new ninja "rule" statement for a given command. @@ -1942,13 +1946,14 @@ def WriteNewNinjaRule( if self.flavor == "win": rspfile = rule_name + ".$unique_name.rsp" # The cygwin case handles this inside the bash sub-shell. - run_in = "" if is_cygwin else " " + self.build_to_base - if is_cygwin: + run_in = "" if win_shell_flags.cygwin else " " + self.build_to_base + if win_shell_flags.cygwin: rspfile_content = self.msvs_settings.BuildCygwinBashCommandLine( args, self.build_to_base ) else: - rspfile_content = gyp.msvs_emulation.EncodeRspFileList(args) + rspfile_content = gyp.msvs_emulation.EncodeRspFileList( + args, win_shell_flags.quote) command = ( "%s gyp-win-tool action-wrapper $arch " % sys.executable + rspfile @@ -2107,8 +2112,8 @@ class MEMORYSTATUSEX(ctypes.Structure): ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat)) # VS 2015 uses 20% more working set than VS 2013 and can consume all RAM - # on a 64 GB machine. - mem_limit = max(1, stat.ullTotalPhys // (5 * (2 ** 30))) # total / 5GB + # on a 64 GiB machine. + mem_limit = max(1, stat.ullTotalPhys // (5 * (2 ** 30))) # total / 5GiB hard_cap = max(1, int(os.environ.get("GYP_LINK_CONCURRENCY_MAX", 2 ** 32))) return min(mem_limit, hard_cap) elif sys.platform.startswith("linux"): @@ -2385,7 +2390,6 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, config_name ) if flavor == "win": master_ninja.variable("ld_host", ld_host) - master_ninja.variable("ldxx_host", ldxx_host) else: master_ninja.variable( "ld_host", CommandWithWrapper("LINK", wrappers, ld_host) @@ -2492,7 +2496,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, config_name ), ) - if flavor != "mac" and flavor != "win": + if flavor not in ("ios", "mac", "win"): master_ninja.rule( "alink", description="AR $out", diff --git a/gyp/pylib/gyp/generator/ninja_test.py b/gyp/pylib/gyp/generator/ninja_test.py index abadcd9828..7d180685b2 100644 --- a/gyp/pylib/gyp/generator/ninja_test.py +++ b/gyp/pylib/gyp/generator/ninja_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/gyp/pylib/gyp/generator/xcode_test.py b/gyp/pylib/gyp/generator/xcode_test.py index 51fbca6a2a..49772d1f4d 100644 --- a/gyp/pylib/gyp/generator/xcode_test.py +++ b/gyp/pylib/gyp/generator/xcode_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2013 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/gyp/pylib/gyp/input.py b/gyp/pylib/gyp/input.py index ca7ce44eab..d9699a0a50 100644 --- a/gyp/pylib/gyp/input.py +++ b/gyp/pylib/gyp/input.py @@ -225,7 +225,7 @@ def LoadOneBuildFile(build_file_path, data, aux_data, includes, is_target, check return data[build_file_path] if os.path.exists(build_file_path): - build_file_contents = open(build_file_path).read() + build_file_contents = open(build_file_path, encoding='utf-8').read() else: raise GypError(f"{build_file_path} not found (cwd: {os.getcwd()})") @@ -961,13 +961,13 @@ def ExpandVariables(input, phase, variables, build_file): # Fix up command with platform specific workarounds. contents = FixupPlatformCommand(contents) try: - p = subprocess.Popen( + # stderr will be printed no matter what + result = subprocess.run( contents, - shell=use_shell, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE, + shell=use_shell, cwd=build_file_dir, + check=False ) except Exception as e: raise GypError( @@ -975,19 +975,12 @@ def ExpandVariables(input, phase, variables, build_file): % (e, contents, build_file) ) - p_stdout, p_stderr = p.communicate("") - p_stdout = p_stdout.decode("utf-8") - p_stderr = p_stderr.decode("utf-8") - - if p.wait() != 0 or p_stderr: - sys.stderr.write(p_stderr) - # Simulate check_call behavior, since check_call only exists - # in python 2.5 and later. + if result.returncode > 0: raise GypError( "Call to '%s' returned exit status %d while in %s." - % (contents, p.returncode, build_file) + % (contents, result.returncode, build_file) ) - replacement = p_stdout.rstrip() + replacement = result.stdout.decode("utf-8").rstrip() cached_command_results[cache_key] = replacement else: diff --git a/gyp/pylib/gyp/input_test.py b/gyp/pylib/gyp/input_test.py index 6672ddc014..a18f72e9eb 100755 --- a/gyp/pylib/gyp/input_test.py +++ b/gyp/pylib/gyp/input_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2013 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/gyp/pylib/gyp/mac_tool.py b/gyp/pylib/gyp/mac_tool.py index 1cd8e3798f..59647c9a89 100755 --- a/gyp/pylib/gyp/mac_tool.py +++ b/gyp/pylib/gyp/mac_tool.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. diff --git a/gyp/pylib/gyp/msvs_emulation.py b/gyp/pylib/gyp/msvs_emulation.py index f744e38df1..5b9c2712e0 100644 --- a/gyp/pylib/gyp/msvs_emulation.py +++ b/gyp/pylib/gyp/msvs_emulation.py @@ -7,6 +7,7 @@ build systems, primarily ninja. """ +import collections import os import re import subprocess @@ -19,7 +20,7 @@ windows_quoter_regex = re.compile(r'(\\*)"') -def QuoteForRspFile(arg): +def QuoteForRspFile(arg, quote_cmd=True): """Quote a command line argument so that it appears as one argument when processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for Windows programs).""" @@ -36,7 +37,8 @@ def QuoteForRspFile(arg): # For a literal quote, CommandLineToArgvW requires 2n+1 backslashes # preceding it, and results in n backslashes + the quote. So we substitute # in 2* what we match, +1 more, plus the quote. - arg = windows_quoter_regex.sub(lambda mo: 2 * mo.group(1) + '\\"', arg) + if quote_cmd: + arg = windows_quoter_regex.sub(lambda mo: 2 * mo.group(1) + '\\"', arg) # %'s also need to be doubled otherwise they're interpreted as batch # positional arguments. Also make sure to escape the % so that they're @@ -48,12 +50,17 @@ def QuoteForRspFile(arg): # These commands are used in rsp files, so no escaping for the shell (via ^) # is necessary. - # Finally, wrap the whole thing in quotes so that the above quote rule - # applies and whitespace isn't a word break. - return '"' + arg + '"' + # As a workaround for programs that don't use CommandLineToArgvW, gyp + # supports msvs_quote_cmd=0, which simply disables all quoting. + if quote_cmd: + # Finally, wrap the whole thing in quotes so that the above quote rule + # applies and whitespace isn't a word break. + return f'"{arg}"' + return arg -def EncodeRspFileList(args): + +def EncodeRspFileList(args, quote_cmd): """Process a list of arguments using QuoteCmdExeArgument.""" # Note that the first argument is assumed to be the command. Don't add # quotes around it because then built-ins like 'echo', etc. won't work. @@ -67,7 +74,8 @@ def EncodeRspFileList(args): program = call + " " + os.path.normpath(program) else: program = os.path.normpath(args[0]) - return program + " " + " ".join(QuoteForRspFile(arg) for arg in args[1:]) + return (program + " " + + " ".join(QuoteForRspFile(arg, quote_cmd) for arg in args[1:])) def _GenericRetrieve(root, default, path): @@ -333,7 +341,7 @@ def _TargetConfig(self, config): # first level is globally for the configuration (this is what we consider # "the" config at the gyp level, which will be something like 'Debug' or # 'Release'), VS2015 and later only use this level - if self.vs_version.short_name >= 2015: + if int(self.vs_version.short_name) >= 2015: return config # and a second target-specific configuration, which is an # override for the global one. |config| is remapped here to take into @@ -537,7 +545,7 @@ def GetCflags(self, config): ) ] ) - if self.vs_version.project_version >= 12.0: + if float(self.vs_version.project_version) >= 12.0: # New flag introduced in VS2013 (project version 12.0) Forces writes to # the program database (PDB) to be serialized through MSPDBSRV.EXE. # https://msdn.microsoft.com/en-us/library/dn502518.aspx @@ -933,13 +941,22 @@ def BuildCygwinBashCommandLine(self, args, path_to_base): ) return cmd - def IsRuleRunUnderCygwin(self, rule): - """Determine if an action should be run under cygwin. If the variable is - unset, or set to 1 we use cygwin.""" - return ( - int(rule.get("msvs_cygwin_shell", self.spec.get("msvs_cygwin_shell", 1))) - != 0 - ) + RuleShellFlags = collections.namedtuple("RuleShellFlags", ["cygwin", "quote"]) + + def GetRuleShellFlags(self, rule): + """Return RuleShellFlags about how the given rule should be run. This + includes whether it should run under cygwin (msvs_cygwin_shell), and + whether the commands should be quoted (msvs_quote_cmd).""" + # If the variable is unset, or set to 1 we use cygwin + cygwin = int(rule.get("msvs_cygwin_shell", + self.spec.get("msvs_cygwin_shell", 1))) != 0 + # Default to quoting. There's only a few special instances where the + # target command uses non-standard command line parsing and handle quotes + # and quote escaping differently. + quote_cmd = int(rule.get("msvs_quote_cmd", 1)) + assert quote_cmd != 0 or cygwin != 1, \ + "msvs_quote_cmd=0 only applicable for msvs_cygwin_shell=0" + return MsvsSettings.RuleShellFlags(cygwin, quote_cmd) def _HasExplicitRuleForExtension(self, spec, extension): """Determine if there's an explicit rule for a particular extension.""" diff --git a/gyp/pylib/gyp/win_tool.py b/gyp/pylib/gyp/win_tool.py index 7e85946720..638eee4002 100755 --- a/gyp/pylib/gyp/win_tool.py +++ b/gyp/pylib/gyp/win_tool.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be @@ -221,8 +221,9 @@ def ExecLinkWithManifests( # and sometimes doesn't unfortunately. with open(our_manifest) as our_f: with open(assert_manifest) as assert_f: - our_data = our_f.read().translate(None, string.whitespace) - assert_data = assert_f.read().translate(None, string.whitespace) + translator = str.maketrans('', '', string.whitespace) + our_data = our_f.read().translate(translator) + assert_data = assert_f.read().translate(translator) if our_data != assert_data: os.unlink(out) diff --git a/gyp/pylib/gyp/xcodeproj_file.py b/gyp/pylib/gyp/xcodeproj_file.py index bca4fb79d0..4e0ec5e882 100644 --- a/gyp/pylib/gyp/xcodeproj_file.py +++ b/gyp/pylib/gyp/xcodeproj_file.py @@ -138,7 +138,9 @@ """ import gyp.common +from functools import cmp_to_key import hashlib +from operator import attrgetter import posixpath import re import struct @@ -297,8 +299,8 @@ def __repr__(self): try: name = self.Name() except NotImplementedError: - return "<{} at 0x{:x}>".format(self.__class__.__name__, id(self)) - return "<{} {!r} at 0x{:x}>".format(self.__class__.__name__, name, id(self)) + return f"<{self.__class__.__name__} at 0x{id(self):x}>" + return f"<{self.__class__.__name__} {name!r} at 0x{id(self):x}>" def Copy(self): """Make a copy of this object. @@ -423,6 +425,8 @@ def _HashUpdate(hash, data): """ hash.update(struct.pack(">i", len(data))) + if isinstance(data, str): + data = data.encode("utf-8") hash.update(data) if seed_hash is None: @@ -1483,7 +1487,7 @@ def TakeOverOnlyChild(self, recurse=False): def SortGroup(self): self._properties["children"] = sorted( - self._properties["children"], cmp=lambda x, y: x.Compare(y) + self._properties["children"], key=cmp_to_key(lambda x, y: x.Compare(y)) ) # Recurse. @@ -2247,7 +2251,7 @@ class PBXContainerItemProxy(XCObject): def __repr__(self): props = self._properties name = "{}.gyp:{}".format(props["containerPortal"].Name(), props["remoteInfo"]) - return "<{} {!r} at 0x{:x}>".format(self.__class__.__name__, name, id(self)) + return f"<{self.__class__.__name__} {name!r} at 0x{id(self):x}>" def Name(self): # Admittedly not the best name, but it's what Xcode uses. @@ -2284,7 +2288,7 @@ class PBXTargetDependency(XCObject): def __repr__(self): name = self._properties.get("name") or self._properties["target"].Name() - return "<{} {!r} at 0x{:x}>".format(self.__class__.__name__, name, id(self)) + return f"<{self.__class__.__name__} {name!r} at 0x{id(self):x}>" def Name(self): # Admittedly not the best name, but it's what Xcode uses. @@ -2766,7 +2770,7 @@ def __init__(self, properties=None, id=None, parent=None, path=None): self.path = path self._other_pbxprojects = {} # super - return XCContainerPortal.__init__(self, properties, id, parent) + XCContainerPortal.__init__(self, properties, id, parent) def Name(self): name = self.path @@ -2891,7 +2895,7 @@ def SortGroups(self): # according to their defined order. self._properties["mainGroup"]._properties["children"] = sorted( self._properties["mainGroup"]._properties["children"], - cmp=lambda x, y: x.CompareRootGroup(y), + key=cmp_to_key(lambda x, y: x.CompareRootGroup(y)), ) # Sort everything else by putting group before files, and going @@ -2986,9 +2990,7 @@ def AddOrGetProjectReference(self, other_pbxproject): # Xcode seems to sort this list case-insensitively self._properties["projectReferences"] = sorted( self._properties["projectReferences"], - cmp=lambda x, y: cmp( - x["ProjectRef"].Name().lower(), y["ProjectRef"].Name().lower() - ), + key=lambda x: x["ProjectRef"].Name().lower() ) else: # The link already exists. Pull out the relevnt data. @@ -3120,7 +3122,8 @@ def CompareProducts(x, y, remote_products): product_group = ref_dict["ProductGroup"] product_group._properties["children"] = sorted( product_group._properties["children"], - cmp=lambda x, y, rp=remote_products: CompareProducts(x, y, rp), + key=cmp_to_key( + lambda x, y, rp=remote_products: CompareProducts(x, y, rp)), ) @@ -3155,7 +3158,7 @@ def Print(self, file=sys.stdout): else: self._XCPrint(file, 0, "{\n") for property, value in sorted( - self._properties.items(), cmp=lambda x, y: cmp(x, y) + self._properties.items() ): if property == "objects": self._PrintObjects(file) @@ -3183,7 +3186,7 @@ def _PrintObjects(self, file): self._XCPrint(file, 0, "\n") self._XCPrint(file, 0, "/* Begin " + class_name + " section */\n") for object in sorted( - objects_by_class[class_name], cmp=lambda x, y: cmp(x.id, y.id) + objects_by_class[class_name], key=attrgetter("id") ): object.Print(file) self._XCPrint(file, 0, "/* End " + class_name + " section */\n") diff --git a/gyp/pyproject.toml b/gyp/pyproject.toml new file mode 100644 index 0000000000..d8a5451520 --- /dev/null +++ b/gyp/pyproject.toml @@ -0,0 +1,41 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "gyp-next" +version = "0.14.0" +authors = [ + { name="Node.js contributors", email="ryzokuken@disroot.org" }, +] +description = "A fork of the GYP build system for use in the Node.js projects" +readme = "README.md" +license = { file="LICENSE" } +requires-python = ">=3.6" +classifiers = [ + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", +] + +[project.optional-dependencies] +dev = ["flake8", "pytest"] + +[project.scripts] +gyp = "gyp:script_main" + +[project.urls] +"Homepage" = "https://github.com/nodejs/gyp-next" + +[tool.setuptools] +package-dir = {"" = "pylib"} +packages = ["gyp", "gyp.generator"] diff --git a/gyp/requirements_dev.txt b/gyp/requirements_dev.txt deleted file mode 100644 index 28ecacab60..0000000000 --- a/gyp/requirements_dev.txt +++ /dev/null @@ -1,2 +0,0 @@ -flake8 -pytest diff --git a/gyp/setup.py b/gyp/setup.py deleted file mode 100644 index 4ff447fc8b..0000000000 --- a/gyp/setup.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2009 Google Inc. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -from os import path - -from setuptools import setup - -here = path.abspath(path.dirname(__file__)) -# Get the long description from the README file -with open(path.join(here, "README.md")) as in_file: - long_description = in_file.read() - -setup( - name="gyp-next", - version="0.8.0", - description="A fork of the GYP build system for use in the Node.js projects", - long_description=long_description, - long_description_content_type="text/markdown", - author="Node.js contributors", - author_email="ryzokuken@disroot.org", - url="https://github.com/nodejs/gyp-next", - package_dir={"": "pylib"}, - packages=["gyp", "gyp.generator"], - entry_points={"console_scripts": ["gyp=gyp:script_main"]}, - python_requires=">=3.6", - classifiers=[ - "Development Status :: 3 - Alpha", - "Environment :: Console", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Natural Language :: English", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - ], -) diff --git a/gyp/test_gyp.py b/gyp/test_gyp.py index 8ee2e48c1e..b7bb956b8e 100755 --- a/gyp/test_gyp.py +++ b/gyp/test_gyp.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -116,6 +116,7 @@ def main(argv=None): else: format_list = { "aix5": ["make"], + "os400": ["make"], "freebsd7": ["make"], "freebsd8": ["make"], "openbsd5": ["make"], @@ -140,10 +141,7 @@ def main(argv=None): if not args.quiet: runner.print_results() - if runner.failures: - return 1 - else: - return 0 + return 1 if runner.failures else 0 def print_configuration_info(): @@ -152,8 +150,8 @@ def print_configuration_info(): sys.path.append(os.path.abspath("test/lib")) import TestMac - print(" Mac {} {}".format(platform.mac_ver()[0], platform.mac_ver()[2])) - print(" Xcode %s" % TestMac.Xcode.Version()) + print(f" Mac {platform.mac_ver()[0]} {platform.mac_ver()[2]}") + print(f" Xcode {TestMac.Xcode.Version()}") elif sys.platform == "win32": sys.path.append(os.path.abspath("pylib")) import gyp.MSVSVersion @@ -162,8 +160,8 @@ def print_configuration_info(): print(" MSVS %s" % gyp.MSVSVersion.SelectVisualStudioVersion().Description()) elif sys.platform in ("linux", "linux2"): print(" Linux %s" % " ".join(platform.linux_distribution())) - print(" Python %s" % platform.python_version()) - print(" PYTHONPATH=%s" % os.environ["PYTHONPATH"]) + print(f" Python {platform.python_version()}") + print(f" PYTHONPATH={os.environ['PYTHONPATH']}") print() @@ -222,13 +220,9 @@ def run_test(self, test, fmt, i): res_msg = f" {res} {took:.3f}s" self.print_(res_msg) - if ( - stdout - and not stdout.endswith("PASSED\n") - and not (stdout.endswith("NO RESULT\n")) - ): + if stdout and not stdout.endswith(("PASSED\n", "NO RESULT\n")): print() - print("\n".join(" %s" % line for line in stdout.splitlines())) + print("\n".join(f" {line}" for line in stdout.splitlines())) elif not self.isatty: print() diff --git a/gyp/tools/emacs/gyp-tests.el b/gyp/tools/emacs/gyp-tests.el index 11b8497886..07afc58a93 100644 --- a/gyp/tools/emacs/gyp-tests.el +++ b/gyp/tools/emacs/gyp-tests.el @@ -30,7 +30,7 @@ "For the purposes of face comparison, we're not interested in the differences between certain faces. For example, the difference between font-lock-comment-delimiter and font-lock-comment-face." - (case face + (cl-case face ((font-lock-comment-delimiter-face) font-lock-comment-face) (t face))) diff --git a/gyp/tools/emacs/gyp.el b/gyp/tools/emacs/gyp.el index b98b155ced..042ff3a925 100644 --- a/gyp/tools/emacs/gyp.el +++ b/gyp/tools/emacs/gyp.el @@ -213,7 +213,7 @@ string-start) (setq string-start (gyp-parse-to limit)) (if string-start - (setq group (case (gyp-section-at-point) + (setq group (cl-case (gyp-section-at-point) ('dependencies 1) ('variables 2) ('conditions 2) diff --git a/gyp/tools/graphviz.py b/gyp/tools/graphviz.py index 9005d2c55a..f19426b69f 100755 --- a/gyp/tools/graphviz.py +++ b/gyp/tools/graphviz.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2011 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/gyp/tools/pretty_gyp.py b/gyp/tools/pretty_gyp.py index c8c7578fda..6eef3a1bbf 100755 --- a/gyp/tools/pretty_gyp.py +++ b/gyp/tools/pretty_gyp.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be @@ -90,7 +90,7 @@ def count_braces(line): """ open_braces = ["[", "(", "{"] close_braces = ["]", ")", "}"] - closing_prefix_re = re.compile(r"(.*?[^\s\]\}\)]+.*?)([\]\}\)],?)\s*$") + closing_prefix_re = re.compile(r"[^\s\]\}\)]\s*[\]\}\)]+,?\s*$") cnt = 0 stripline = COMMENT_RE.sub(r"", line) stripline = QUOTE_RE.sub(r"''", stripline) diff --git a/gyp/tools/pretty_sln.py b/gyp/tools/pretty_sln.py index 87c03b8880..6ca0cd12a7 100755 --- a/gyp/tools/pretty_sln.py +++ b/gyp/tools/pretty_sln.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/gyp/tools/pretty_vcproj.py b/gyp/tools/pretty_vcproj.py index 23ef7c9727..00d32debda 100755 --- a/gyp/tools/pretty_vcproj.py +++ b/gyp/tools/pretty_vcproj.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012 Google Inc. All rights reserved. # Use of this source code is governed by a BSD-style license that can be diff --git a/lib/build.js b/lib/build.js index 063d866865..c122b9ff18 100644 --- a/lib/build.js +++ b/lib/build.js @@ -1,16 +1,19 @@ 'use strict' -const fs = require('graceful-fs') +const fs = require('graceful-fs').promises +const { promisify } = require('util') const path = require('path') -const glob = require('glob') -const log = require('npmlog') +const glob = promisify(require('glob')) +const log = require('./log') const which = require('which') const win = process.platform === 'win32' -function build (gyp, argv, callback) { - var platformMake = 'make' +async function build (gyp, argv) { + let platformMake = 'make' if (process.platform === 'aix') { platformMake = 'gmake' + } else if (process.platform === 'os400') { + platformMake = 'gmake' } else if (process.platform.indexOf('bsd') !== -1) { platformMake = 'gmake' } else if (win && argv.length > 0) { @@ -19,113 +22,107 @@ function build (gyp, argv, callback) { }) } - var makeCommand = gyp.opts.make || process.env.MAKE || platformMake - var command = win ? 'msbuild' : makeCommand - var jobs = gyp.opts.jobs || process.env.JOBS - var buildType - var config - var arch - var nodeDir - var guessedSolution + const makeCommand = gyp.opts.make || process.env.MAKE || platformMake + let command = win ? 'msbuild' : makeCommand + const jobs = gyp.opts.jobs || process.env.JOBS + let buildType + let config + let arch + let nodeDir + let guessedSolution + let python + let buildBinsDir - loadConfigGypi() + await loadConfigGypi() /** * Load the "config.gypi" file that was generated during "configure". */ - function loadConfigGypi () { - var configPath = path.resolve('build', 'config.gypi') - - fs.readFile(configPath, 'utf8', function (err, data) { - if (err) { - if (err.code === 'ENOENT') { - callback(new Error('You must run `node-gyp configure` first!')) - } else { - callback(err) - } - return + async function loadConfigGypi () { + let data + try { + const configPath = path.resolve('build', 'config.gypi') + data = await fs.readFile(configPath, 'utf8') + } catch (err) { + if (err.code === 'ENOENT') { + throw new Error('You must run `node-gyp configure` first!') + } else { + throw err } - config = JSON.parse(data.replace(/#.+\r?\n/, '')) + } - // get the 'arch', 'buildType', and 'nodeDir' vars from the config - buildType = config.target_defaults.default_configuration - arch = config.variables.target_arch - nodeDir = config.variables.nodedir + config = JSON.parse(data.replace(/#.+\r?\n/, '')) - if ('debug' in gyp.opts) { - buildType = gyp.opts.debug ? 'Debug' : 'Release' - } - if (!buildType) { - buildType = 'Release' - } + // get the 'arch', 'buildType', and 'nodeDir' vars from the config + buildType = config.target_defaults.default_configuration + arch = config.variables.target_arch + nodeDir = config.variables.nodedir + python = config.variables.python + + if ('debug' in gyp.opts) { + buildType = gyp.opts.debug ? 'Debug' : 'Release' + } + if (!buildType) { + buildType = 'Release' + } - log.verbose('build type', buildType) - log.verbose('architecture', arch) - log.verbose('node dev dir', nodeDir) + log.verbose('build type', buildType) + log.verbose('architecture', arch) + log.verbose('node dev dir', nodeDir) + log.verbose('python', python) - if (win) { - findSolutionFile() - } else { - doWhich() - } - }) + if (win) { + await findSolutionFile() + } else { + await doWhich() + } } /** * On Windows, find the first build/*.sln file. */ - function findSolutionFile () { - glob('build/*.sln', function (err, files) { - if (err) { - return callback(err) - } - if (files.length === 0) { - return callback(new Error('Could not find *.sln file. Did you run "configure"?')) - } - guessedSolution = files[0] - log.verbose('found first Solution file', guessedSolution) - doWhich() - }) + async function findSolutionFile () { + const files = await glob('build/*.sln') + if (files.length === 0) { + throw new Error('Could not find *.sln file. Did you run "configure"?') + } + guessedSolution = files[0] + log.verbose('found first Solution file', guessedSolution) + await doWhich() } /** * Uses node-which to locate the msbuild / make executable. */ - function doWhich () { + async function doWhich () { // On Windows use msbuild provided by node-gyp configure if (win) { if (!config.variables.msbuild_path) { - return callback(new Error( - 'MSBuild is not set, please run `node-gyp configure`.')) + throw new Error('MSBuild is not set, please run `node-gyp configure`.') } command = config.variables.msbuild_path log.verbose('using MSBuild:', command) - doBuild() + await doBuild() return } + // First make sure we have the build command in the PATH - which(command, function (err, execPath) { - if (err) { - // Some other error or 'make' not found on Unix, report that to the user - callback(err) - return - } - log.verbose('`which` succeeded for `' + command + '`', execPath) - doBuild() - }) + const execPath = await which(command) + log.verbose('`which` succeeded for `' + command + '`', execPath) + await doBuild() } /** * Actually spawn the process and compile the module. */ - function doBuild () { + async function doBuild () { // Enable Verbose build - var verbose = log.levels[log.level] <= log.levels.verbose - var j + const verbose = log.logger.isVisible('verbose') + let j if (!win && verbose) { argv.push('V=1') @@ -145,10 +142,12 @@ function build (gyp, argv, callback) { // Convert .gypi config target_arch to MSBuild /Platform // Since there are many ways to state '32-bit Intel', default to it. // N.B. msbuild's Condition string equality tests are case-insensitive. - var archLower = arch.toLowerCase() - var p = archLower === 'x64' ? 'x64' - : (archLower === 'arm' ? 'ARM' - : (archLower === 'arm64' ? 'ARM64' : 'Win32')) + const archLower = arch.toLowerCase() + const p = archLower === 'x64' + ? 'x64' + : (archLower === 'arm' + ? 'ARM' + : (archLower === 'arm64' ? 'ARM64' : 'Win32')) argv.push('/p:Configuration=' + buildType + ';Platform=' + p) if (jobs) { j = parseInt(jobs, 10) @@ -177,7 +176,7 @@ function build (gyp, argv, callback) { if (win) { // did the user specify their own .sln file? - var hasSln = argv.some(function (arg) { + const hasSln = argv.some(function (arg) { return path.extname(arg) === '.sln' }) if (!hasSln) { @@ -185,20 +184,46 @@ function build (gyp, argv, callback) { } } - var proc = gyp.spawn(command, argv) - proc.on('exit', onExit) - } - - function onExit (code, signal) { - if (code !== 0) { - return callback(new Error('`' + command + '` failed with exit code: ' + code)) - } - if (signal) { - return callback(new Error('`' + command + '` got signal: ' + signal)) + if (!win) { + // Add build-time dependency symlinks (such as Python) to PATH + buildBinsDir = path.resolve('build', 'node_gyp_bins') + process.env.PATH = `${buildBinsDir}:${process.env.PATH}` + await fs.mkdir(buildBinsDir, { recursive: true }) + const symlinkDestination = path.join(buildBinsDir, 'python3') + try { + await fs.unlink(symlinkDestination) + } catch (err) { + if (err.code !== 'ENOENT') throw err + } + await fs.symlink(python, symlinkDestination) + log.verbose('bin symlinks', `created symlink to "${python}" in "${buildBinsDir}" and added to PATH`) } - callback() + + const proc = gyp.spawn(command, argv) + await new Promise((resolve, reject) => proc.on('exit', async (code, signal) => { + if (buildBinsDir) { + // Clean up the build-time dependency symlinks: + if (fs.rm) { + // fs.rm is only available in Node 14+ + await fs.rm(buildBinsDir, { recursive: true }) + } else { + // Only used for old node, as recursive rmdir is deprecated in Node 14+ + await fs.rmdir(buildBinsDir, { recursive: true }) + } + } + + if (code !== 0) { + return reject(new Error('`' + command + '` failed with exit code: ' + code)) + } + if (signal) { + return reject(new Error('`' + command + '` got signal: ' + signal)) + } + resolve() + })) } } -module.exports = build +module.exports = function (gyp, argv, callback) { + build(gyp, argv).then(callback.bind(undefined, null), callback) +} module.exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module' diff --git a/lib/clean.js b/lib/clean.js index dbfa4dbb99..844b47aed1 100644 --- a/lib/clean.js +++ b/lib/clean.js @@ -1,15 +1,17 @@ 'use strict' -const rm = require('rimraf') -const log = require('npmlog') +const fs = require('fs/promises') +const log = require('./log') -function clean (gyp, argv, callback) { +async function clean (gyp, argv) { // Remove the 'build' dir - var buildDir = 'build' + const buildDir = 'build' log.verbose('clean', 'removing "%s" directory', buildDir) - rm(buildDir, callback) + await fs.rm(buildDir, { recursive: true, force: true }) } -module.exports = clean +module.exports = function (gyp, argv, callback) { + clean(gyp, argv).then(callback.bind(undefined, null), callback) +} module.exports.usage = 'Removes any generated build files and the "out" dir' diff --git a/lib/configure.js b/lib/configure.js index d4342b9d76..01c3f497ad 100644 --- a/lib/configure.js +++ b/lib/configure.js @@ -2,24 +2,26 @@ const fs = require('graceful-fs') const path = require('path') -const log = require('npmlog') +const log = require('./log') const os = require('os') const processRelease = require('./process-release') const win = process.platform === 'win32' const findNodeDirectory = require('./find-node-directory') +const createConfigGypi = require('./create-config-gypi') const msgFormat = require('util').format -var findPython = require('./find-python') +const findPython = require('./find-python') +let findVisualStudio if (win) { - var findVisualStudio = require('./find-visualstudio') + findVisualStudio = require('./find-visualstudio') } function configure (gyp, argv, callback) { - var python - var buildDir = path.resolve('build') - var configNames = ['config.gypi', 'common.gypi'] - var configs = [] - var nodeDir - var release = processRelease(argv, gyp, process.version, process.release) + let python + const buildDir = path.resolve('build') + const configNames = ['config.gypi', 'common.gypi'] + const configs = [] + let nodeDir + const release = processRelease(argv, gyp, process.version, process.release) findPython(gyp.opts.python, function (err, found) { if (err) { @@ -72,13 +74,16 @@ function configure (gyp, argv, callback) { function createBuildDir () { log.verbose('build dir', 'attempting to create "build" dir: %s', buildDir) + fs.mkdir(buildDir, { recursive: true }, function (err, isNew) { if (err) { return callback(err) } - log.verbose('build dir', '"build" dir needed to be created?', isNew) + log.verbose( + 'build dir', '"build" dir needed to be created?', isNew ? 'Yes' : 'No' + ) if (win) { - findVisualStudio(release.semver, gyp.opts.msvs_version, + findVisualStudio(release.semver, gyp.opts['msvs-version'], createConfigFile) } else { createConfigFile() @@ -90,119 +95,24 @@ function configure (gyp, argv, callback) { if (err) { return callback(err) } - - var configFilename = 'config.gypi' - var configPath = path.resolve(buildDir, configFilename) - - log.verbose('build/' + configFilename, 'creating config file') - - var config = process.config || {} - var defaults = config.target_defaults - var variables = config.variables - - // default "config.variables" - if (!variables) { - variables = config.variables = {} - } - - // default "config.defaults" - if (!defaults) { - defaults = config.target_defaults = {} - } - - // don't inherit the "defaults" from node's `process.config` object. - // doing so could cause problems in cases where the `node` executable was - // compiled on a different machine (with different lib/include paths) than - // the machine where the addon is being built to - defaults.cflags = [] - defaults.defines = [] - defaults.include_dirs = [] - defaults.libraries = [] - - // set the default_configuration prop - if ('debug' in gyp.opts) { - defaults.default_configuration = gyp.opts.debug ? 'Debug' : 'Release' - } - - if (!defaults.default_configuration) { - defaults.default_configuration = 'Release' - } - - // set the target_arch variable - variables.target_arch = gyp.opts.arch || process.arch || 'ia32' - if (variables.target_arch === 'arm64') { - defaults.msvs_configuration_platform = 'ARM64' - defaults.xcode_configuration_platform = 'arm64' - } - - // set the node development directory - variables.nodedir = nodeDir - - // disable -T "thin" static archives by default - variables.standalone_static_library = gyp.opts.thin ? 0 : 1 - - if (win) { + if (process.platform === 'win32') { process.env.GYP_MSVS_VERSION = Math.min(vsInfo.versionYear, 2015) process.env.GYP_MSVS_OVERRIDE_PATH = vsInfo.path - defaults.msbuild_toolset = vsInfo.toolset - if (vsInfo.sdk) { - defaults.msvs_windows_target_platform_version = vsInfo.sdk - } - if (variables.target_arch === 'arm64') { - if (vsInfo.versionMajor > 15 || - (vsInfo.versionMajor === 15 && vsInfo.versionMajor >= 9)) { - defaults.msvs_enable_marmasm = 1 - } else { - log.warn('Compiling ARM64 assembly is only available in\n' + - 'Visual Studio 2017 version 15.9 and above') - } - } - variables.msbuild_path = vsInfo.msBuild } - - // loop through the rest of the opts and add the unknown ones as variables. - // this allows for module-specific configure flags like: - // - // $ node-gyp configure --shared-libxml2 - Object.keys(gyp.opts).forEach(function (opt) { - if (opt === 'argv') { - return - } - if (opt in gyp.configDefs) { - return - } - variables[opt.replace(/-/g, '_')] = gyp.opts[opt] + createConfigGypi({ gyp, buildDir, nodeDir, vsInfo, python }).then(configPath => { + configs.push(configPath) + findConfigs() + }).catch(err => { + callback(err) }) - - // ensures that any boolean values from `process.config` get stringified - function boolsToString (k, v) { - if (typeof v === 'boolean') { - return String(v) - } - return v - } - - log.silly('build/' + configFilename, config) - - // now write out the config.gypi file to the build/ dir - var prefix = '# Do not edit. File was generated by node-gyp\'s "configure" step' - - var json = JSON.stringify(config, boolsToString, 2) - log.verbose('build/' + configFilename, 'writing out config file: %s', configPath) - configs.push(configPath) - fs.writeFile(configPath, [prefix, json, ''].join('\n'), findConfigs) } - function findConfigs (err) { - if (err) { - return callback(err) - } - - var name = configNames.shift() + function findConfigs () { + const name = configNames.shift() if (!name) { return runGyp() } - var fullPath = path.resolve(name) + const fullPath = path.resolve(name) log.verbose(name, 'checking for gypi file: %s', fullPath) fs.stat(fullPath, function (err) { @@ -244,13 +154,15 @@ function configure (gyp, argv, callback) { // For AIX and z/OS we need to set up the path to the exports file // which contains the symbols needed for linking. - var nodeExpFile - if (process.platform === 'aix' || process.platform === 'os390') { - var ext = process.platform === 'aix' ? 'exp' : 'x' - var nodeRootDir = findNodeDirectory() - var candidates - - if (process.platform === 'aix') { + let nodeExpFile + let nodeRootDir + let candidates + let logprefix = 'find exports file' + if (process.platform === 'aix' || process.platform === 'os390' || process.platform === 'os400') { + const ext = process.platform === 'os390' ? 'x' : 'exp' + nodeRootDir = findNodeDirectory() + + if (process.platform === 'aix' || process.platform === 'os400') { candidates = [ 'include/node/node', 'out/Release/node', @@ -261,6 +173,8 @@ function configure (gyp, argv, callback) { }) } else { candidates = [ + 'out/Release/lib.target/libnode', + 'out/Debug/lib.target/libnode', 'out/Release/obj.target/libnode', 'out/Debug/obj.target/libnode', 'lib/libnode' @@ -269,34 +183,71 @@ function configure (gyp, argv, callback) { }) } - var logprefix = 'find exports file' nodeExpFile = findAccessibleSync(logprefix, nodeRootDir, candidates) if (nodeExpFile !== undefined) { log.verbose(logprefix, 'Found exports file: %s', nodeExpFile) } else { - var msg = msgFormat('Could not find node.%s file in %s', ext, nodeRootDir) + const msg = msgFormat('Could not find node.%s file in %s', ext, nodeRootDir) log.error(logprefix, 'Could not find exports file') return callback(new Error(msg)) } } + // For z/OS we need to set up the path to zoslib include directory, + // which contains headers included in v8config.h. + let zoslibIncDir + if (process.platform === 'os390') { + logprefix = "find zoslib's zos-base.h:" + let msg + let zoslibIncPath = process.env.ZOSLIB_INCLUDES + if (zoslibIncPath) { + zoslibIncPath = findAccessibleSync(logprefix, zoslibIncPath, ['zos-base.h']) + if (zoslibIncPath === undefined) { + msg = msgFormat('Could not find zos-base.h file in the directory set ' + + 'in ZOSLIB_INCLUDES environment variable: %s; set it ' + + 'to the correct path, or unset it to search %s', process.env.ZOSLIB_INCLUDES, nodeRootDir) + } + } else { + candidates = [ + 'include/node/zoslib/zos-base.h', + 'include/zoslib/zos-base.h', + 'zoslib/include/zos-base.h', + 'install/include/node/zoslib/zos-base.h' + ] + zoslibIncPath = findAccessibleSync(logprefix, nodeRootDir, candidates) + if (zoslibIncPath === undefined) { + msg = msgFormat('Could not find any of %s in directory %s; set ' + + 'environmant variable ZOSLIB_INCLUDES to the path ' + + 'that contains zos-base.h', candidates.toString(), nodeRootDir) + } + } + if (zoslibIncPath !== undefined) { + zoslibIncDir = path.dirname(zoslibIncPath) + log.verbose(logprefix, "Found zoslib's zos-base.h in: %s", zoslibIncDir) + } else if (release.version.split('.')[0] >= 16) { + // zoslib is only shipped in Node v16 and above. + log.error(logprefix, msg) + return callback(new Error(msg)) + } + } + // this logic ported from the old `gyp_addon` python file - var gypScript = path.resolve(__dirname, '..', 'gyp', 'gyp_main.py') - var addonGypi = path.resolve(__dirname, '..', 'addon.gypi') - var commonGypi = path.resolve(nodeDir, 'include/node/common.gypi') + const gypScript = path.resolve(__dirname, '..', 'gyp', 'gyp_main.py') + const addonGypi = path.resolve(__dirname, '..', 'addon.gypi') + let commonGypi = path.resolve(nodeDir, 'include/node/common.gypi') fs.stat(commonGypi, function (err) { if (err) { commonGypi = path.resolve(nodeDir, 'common.gypi') } - var outputDir = 'build' + let outputDir = 'build' if (win) { // Windows expects an absolute path outputDir = buildDir } - var nodeGypDir = path.resolve(__dirname, '..') + const nodeGypDir = path.resolve(__dirname, '..') - var nodeLibFile = path.join(nodeDir, + let nodeLibFile = path.join(nodeDir, !gyp.opts.nodedir ? '<(target_arch)' : '$(Configuration)', release.name + '.lib') @@ -305,8 +256,11 @@ function configure (gyp, argv, callback) { argv.push('-Dlibrary=shared_library') argv.push('-Dvisibility=default') argv.push('-Dnode_root_dir=' + nodeDir) - if (process.platform === 'aix' || process.platform === 'os390') { + if (process.platform === 'aix' || process.platform === 'os390' || process.platform === 'os400') { argv.push('-Dnode_exp_file=' + nodeExpFile) + if (process.platform === 'os390' && zoslibIncDir) { + argv.push('-Dzoslib_include_dir=' + zoslibIncDir) + } } argv.push('-Dnode_gyp_dir=' + nodeGypDir) @@ -335,13 +289,13 @@ function configure (gyp, argv, callback) { argv.unshift(gypScript) // make sure python uses files that came with this particular node package - var pypath = [path.join(__dirname, '..', 'gyp', 'pylib')] + const pypath = [path.join(__dirname, '..', 'gyp', 'pylib')] if (process.env.PYTHONPATH) { pypath.push(process.env.PYTHONPATH) } process.env.PYTHONPATH = pypath.join(win ? ';' : ':') - var cp = gyp.spawn(python, argv) + const cp = gyp.spawn(python, argv) cp.on('exit', onCpExit) }) } @@ -362,10 +316,11 @@ function configure (gyp, argv, callback) { * readable. */ function findAccessibleSync (logprefix, dir, candidates) { - for (var next = 0; next < candidates.length; next++) { - var candidate = path.resolve(dir, candidates[next]) + for (let next = 0; next < candidates.length; next++) { + const candidate = path.resolve(dir, candidates[next]) + let fd try { - var fd = fs.openSync(candidate, 'r') + fd = fs.openSync(candidate, 'r') } catch (e) { // this candidate was not found or not readable, do nothing log.silly(logprefix, 'Could not open %s: %s', candidate, e.message) @@ -381,6 +336,6 @@ function findAccessibleSync (logprefix, dir, candidates) { module.exports = configure module.exports.test = { - findAccessibleSync: findAccessibleSync + findAccessibleSync } module.exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module' diff --git a/lib/create-config-gypi.js b/lib/create-config-gypi.js new file mode 100644 index 0000000000..8687379385 --- /dev/null +++ b/lib/create-config-gypi.js @@ -0,0 +1,150 @@ +'use strict' + +const fs = require('graceful-fs') +const log = require('./log') +const path = require('path') + +function parseConfigGypi (config) { + // translated from tools/js2c.py of Node.js + // 1. string comments + config = config.replace(/#.*/g, '') + // 2. join multiline strings + config = config.replace(/'$\s+'/mg, '') + // 3. normalize string literals from ' into " + config = config.replace(/'/g, '"') + return JSON.parse(config) +} + +async function getBaseConfigGypi ({ gyp, nodeDir }) { + // try reading $nodeDir/include/node/config.gypi first when: + // 1. --dist-url or --nodedir is specified + // 2. and --force-process-config is not specified + const useCustomHeaders = gyp.opts.nodedir || gyp.opts.disturl || gyp.opts['dist-url'] + const shouldReadConfigGypi = useCustomHeaders && !gyp.opts['force-process-config'] + if (shouldReadConfigGypi && nodeDir) { + try { + const baseConfigGypiPath = path.resolve(nodeDir, 'include/node/config.gypi') + const baseConfigGypi = await fs.promises.readFile(baseConfigGypiPath) + return parseConfigGypi(baseConfigGypi.toString()) + } catch (err) { + log.warn('read config.gypi', err.message) + } + } + + // fallback to process.config if it is invalid + return JSON.parse(JSON.stringify(process.config)) +} + +async function getCurrentConfigGypi ({ gyp, nodeDir, vsInfo, python }) { + const config = await getBaseConfigGypi({ gyp, nodeDir }) + if (!config.target_defaults) { + config.target_defaults = {} + } + if (!config.variables) { + config.variables = {} + } + + const defaults = config.target_defaults + const variables = config.variables + + // don't inherit the "defaults" from the base config.gypi. + // doing so could cause problems in cases where the `node` executable was + // compiled on a different machine (with different lib/include paths) than + // the machine where the addon is being built to + defaults.cflags = [] + defaults.defines = [] + defaults.include_dirs = [] + defaults.libraries = [] + + // set the default_configuration prop + if ('debug' in gyp.opts) { + defaults.default_configuration = gyp.opts.debug ? 'Debug' : 'Release' + } + + if (!defaults.default_configuration) { + defaults.default_configuration = 'Release' + } + + // set the target_arch variable + variables.target_arch = gyp.opts.arch || process.arch || 'ia32' + if (variables.target_arch === 'arm64') { + defaults.msvs_configuration_platform = 'ARM64' + defaults.xcode_configuration_platform = 'arm64' + } + + // set the node development directory + variables.nodedir = nodeDir + + // set the configured Python path + variables.python = python + + // disable -T "thin" static archives by default + variables.standalone_static_library = gyp.opts.thin ? 0 : 1 + + if (process.platform === 'win32') { + defaults.msbuild_toolset = vsInfo.toolset + if (vsInfo.sdk) { + defaults.msvs_windows_target_platform_version = vsInfo.sdk + } + if (variables.target_arch === 'arm64') { + if (vsInfo.versionMajor > 15 || + (vsInfo.versionMajor === 15 && vsInfo.versionMajor >= 9)) { + defaults.msvs_enable_marmasm = 1 + } else { + log.warn('Compiling ARM64 assembly is only available in\n' + + 'Visual Studio 2017 version 15.9 and above') + } + } + variables.msbuild_path = vsInfo.msBuild + } + + // loop through the rest of the opts and add the unknown ones as variables. + // this allows for module-specific configure flags like: + // + // $ node-gyp configure --shared-libxml2 + Object.keys(gyp.opts).forEach(function (opt) { + if (opt === 'argv') { + return + } + if (opt in gyp.configDefs) { + return + } + variables[opt.replace(/-/g, '_')] = gyp.opts[opt] + }) + + return config +} + +async function createConfigGypi ({ gyp, buildDir, nodeDir, vsInfo, python }) { + const configFilename = 'config.gypi' + const configPath = path.resolve(buildDir, configFilename) + + log.verbose('build/' + configFilename, 'creating config file') + + const config = await getCurrentConfigGypi({ gyp, nodeDir, vsInfo, python }) + + // ensures that any boolean values in config.gypi get stringified + function boolsToString (k, v) { + if (typeof v === 'boolean') { + return String(v) + } + return v + } + + log.silly('build/' + configFilename, config) + + // now write out the config.gypi file to the build/ dir + const prefix = '# Do not edit. File was generated by node-gyp\'s "configure" step' + + const json = JSON.stringify(config, boolsToString, 2) + log.verbose('build/' + configFilename, 'writing out config file: %s', configPath) + await fs.promises.writeFile(configPath, [prefix, json, ''].join('\n')) + + return configPath +} + +module.exports = createConfigGypi +module.exports.test = { + parseConfigGypi, + getCurrentConfigGypi +} diff --git a/lib/find-node-directory.js b/lib/find-node-directory.js index 0dd781a6cf..8838b81d33 100644 --- a/lib/find-node-directory.js +++ b/lib/find-node-directory.js @@ -1,7 +1,7 @@ 'use strict' const path = require('path') -const log = require('npmlog') +const log = require('./log') function findNodeDirectory (scriptLocation, processObj) { // set dirname and process if not passed in @@ -14,10 +14,10 @@ function findNodeDirectory (scriptLocation, processObj) { } // Have a look to see what is above us, to try and work out where we are - var npmParentDirectory = path.join(scriptLocation, '../../../..') + const npmParentDirectory = path.join(scriptLocation, '../../../..') log.verbose('node-gyp root', 'npm_parent_directory is ' + path.basename(npmParentDirectory)) - var nodeRootDir = '' + let nodeRootDir = '' log.verbose('node-gyp root', 'Finding node root directory') if (path.basename(npmParentDirectory) === 'deps') { @@ -41,8 +41,8 @@ function findNodeDirectory (scriptLocation, processObj) { } else { // We don't know where we are, try working it out from the location // of the node binary - var nodeDir = path.dirname(processObj.execPath) - var directoryUp = path.basename(nodeDir) + const nodeDir = path.dirname(processObj.execPath) + const directoryUp = path.basename(nodeDir) if (directoryUp === 'bin') { nodeRootDir = path.join(nodeDir, '..') } else if (directoryUp === 'Release' || directoryUp === 'Debug') { diff --git a/lib/find-python.js b/lib/find-python.js index af269de2fc..3288839b50 100644 --- a/lib/find-python.js +++ b/lib/find-python.js @@ -1,12 +1,42 @@ 'use strict' -const path = require('path') -const log = require('npmlog') +const log = require('./log') const semver = require('semver') const cp = require('child_process') const extend = require('util')._extend // eslint-disable-line const win = process.platform === 'win32' -const logWithPrefix = require('./util').logWithPrefix + +const systemDrive = process.env.SystemDrive || 'C:' +const username = process.env.USERNAME || process.env.USER || getOsUserInfo() +const localAppData = process.env.LOCALAPPDATA || `${systemDrive}\\${username}\\AppData\\Local` +const foundLocalAppData = process.env.LOCALAPPDATA || username +const programFiles = process.env.ProgramW6432 || process.env.ProgramFiles || `${systemDrive}\\Program Files` +const programFilesX86 = process.env['ProgramFiles(x86)'] || `${programFiles} (x86)` + +const winDefaultLocationsArray = [] +for (const majorMinor of ['311', '310', '39', '38']) { + if (foundLocalAppData) { + winDefaultLocationsArray.push( + `${localAppData}\\Programs\\Python\\Python${majorMinor}\\python.exe`, + `${programFiles}\\Python${majorMinor}\\python.exe`, + `${localAppData}\\Programs\\Python\\Python${majorMinor}-32\\python.exe`, + `${programFiles}\\Python${majorMinor}-32\\python.exe`, + `${programFilesX86}\\Python${majorMinor}-32\\python.exe` + ) + } else { + winDefaultLocationsArray.push( + `${programFiles}\\Python${majorMinor}\\python.exe`, + `${programFiles}\\Python${majorMinor}-32\\python.exe`, + `${programFilesX86}\\Python${majorMinor}-32\\python.exe` + ) + } +} + +function getOsUserInfo () { + try { + return require('os').userInfo().username + } catch (e) {} +} function PythonFinder (configPython, callback) { this.callback = callback @@ -15,20 +45,17 @@ function PythonFinder (configPython, callback) { } PythonFinder.prototype = { - log: logWithPrefix(log, 'find Python'), + log: log.withPrefix('find Python'), argsExecutable: ['-c', 'import sys; print(sys.executable);'], argsVersion: ['-c', 'import sys; print("%s.%s.%s" % sys.version_info[:3]);'], - semverRange: '2.7.x || >=3.5.0', + semverRange: '>=3.6.0', // These can be overridden for testing: execFile: cp.execFile, env: process.env, - win: win, + win, pyLauncher: 'py.exe', - winDefaultLocations: [ - path.join(process.env.SystemDrive || 'C:', 'Python37', 'python.exe'), - path.join(process.env.SystemDrive || 'C:', 'Python27', 'python.exe') - ], + winDefaultLocations: winDefaultLocationsArray, // Logs a message at verbose level, but also saves it to be displayed later // at error level if an error occurs. This should help diagnose the problem. @@ -41,7 +68,7 @@ PythonFinder.prototype = { // Ignore errors, keep trying until Python is found. findPython: function findPython () { const SKIP = 0; const FAIL = 1 - var toCheck = getChecks.apply(this) + const toCheck = getChecks.apply(this) function getChecks () { if (this.env.NODE_GYP_FORCE_PYTHON) { @@ -57,7 +84,7 @@ PythonFinder.prototype = { }] } - var checks = [ + const checks = [ { before: () => { if (!this.configPython) { @@ -86,7 +113,20 @@ PythonFinder.prototype = { }, check: this.checkCommand, arg: this.env.PYTHON - }, + } + ] + + if (this.win) { + checks.push({ + before: () => { + this.addLog( + 'checking if the py launcher can be used to find Python 3') + }, + check: this.checkPyLauncher + }) + } + + checks.push(...[ { before: () => { this.addLog('checking if "python3" can be used') }, check: this.checkCommand, @@ -96,16 +136,11 @@ PythonFinder.prototype = { before: () => { this.addLog('checking if "python" can be used') }, check: this.checkCommand, arg: 'python' - }, - { - before: () => { this.addLog('checking if "python2" can be used') }, - check: this.checkCommand, - arg: 'python2' } - ] + ]) if (this.win) { - for (var i = 0; i < this.winDefaultLocations.length; ++i) { + for (let i = 0; i < this.winDefaultLocations.length; ++i) { const location = this.winDefaultLocations[i] checks.push({ before: () => { @@ -116,13 +151,6 @@ PythonFinder.prototype = { arg: location }) } - checks.push({ - before: () => { - this.addLog( - 'checking if the py launcher can be used to find Python') - }, - check: this.checkPyLauncher - }) } return checks @@ -158,9 +186,9 @@ PythonFinder.prototype = { // Will exit the Python finder on success. // If on Windows, run in a CMD shell to support BAT/CMD launchers. checkCommand: function checkCommand (command, errorCallback) { - var exec = command - var args = this.argsExecutable - var shell = false + let exec = command + let args = this.argsExecutable + let shell = false if (this.win) { // Arguments have to be manually quoted exec = `"${exec}"` @@ -188,10 +216,15 @@ PythonFinder.prototype = { // Distributions of Python on Windows by default install with the "py.exe" // Python launcher which is more likely to exist than the Python executable // being in the $PATH. + // Because the Python launcher supports Python 2 and Python 3, we should + // explicitly request a Python 3 version. This is done by supplying "-3" as + // the first command line argument. Since "py.exe -3" would be an invalid + // executable for "execFile", we have to use the launcher to figure out + // where the actual "python.exe" executable is located. checkPyLauncher: function checkPyLauncher (errorCallback) { this.log.verbose( - `- executing "${this.pyLauncher}" to get Python executable path`) - this.run(this.pyLauncher, this.argsExecutable, false, + `- executing "${this.pyLauncher}" to get Python 3 executable path`) + this.run(this.pyLauncher, ['-3', ...this.argsExecutable], false, function (err, execPath) { // Possible outcomes: same as checkCommand if (err) { @@ -222,7 +255,7 @@ PythonFinder.prototype = { this.addLog(`- version is "${version}"`) const range = new semver.Range(this.semverRange) - var valid = false + let valid = false try { valid = range.test(version) } catch (err) { @@ -244,9 +277,9 @@ PythonFinder.prototype = { // Run an executable or shell command, trimming the output. run: function run (exec, args, shell, callback) { - var env = extend({}, this.env) + const env = extend({}, this.env) env.TERM = 'dumb' - const opts = { env: env, shell: shell } + const opts = { env, shell } this.log.silly('execFile: exec = %j', exec) this.log.silly('execFile: args = %j', args) @@ -278,7 +311,8 @@ PythonFinder.prototype = { fail: function fail () { const errorLog = this.errorLog.join('\n') - const pathExample = this.win ? 'C:\\Path\\To\\python.exe' + const pathExample = this.win + ? 'C:\\Path\\To\\python.exe' : '/path/to/pythonexecutable' // For Windows 80 col console, use up to the column before the one marked // with X (total 79 chars including logger prefix, 58 chars usable here): @@ -305,12 +339,12 @@ PythonFinder.prototype = { } function findPython (configPython, callback) { - var finder = new PythonFinder(configPython, callback) + const finder = new PythonFinder(configPython, callback) finder.findPython() } module.exports = findPython module.exports.test = { - PythonFinder: PythonFinder, - findPython: findPython + PythonFinder, + findPython } diff --git a/lib/find-visualstudio.js b/lib/find-visualstudio.js index 9c6dad90f8..45ef7d3fb1 100644 --- a/lib/find-visualstudio.js +++ b/lib/find-visualstudio.js @@ -1,9 +1,9 @@ 'use strict' -const log = require('npmlog') +const log = require('./log') const execFile = require('child_process').execFile +const fs = require('fs') const path = require('path').win32 -const logWithPrefix = require('./util').logWithPrefix const regSearchKeys = require('./util').regSearchKeys function findVisualStudio (nodeSemver, configMsvsVersion, callback) { @@ -21,9 +21,9 @@ function VisualStudioFinder (nodeSemver, configMsvsVersion, callback) { } VisualStudioFinder.prototype = { - log: logWithPrefix(log, 'find VS'), + log: log.withPrefix('find VS'), - regSearchKeys: regSearchKeys, + regSearchKeys, // Logs a message at verbose level, but also saves it to be displayed later // at error level if an error occurs. This should help diagnose the problem. @@ -125,10 +125,10 @@ VisualStudioFinder.prototype = { // Invoke the PowerShell script to get information about Visual Studio 2017 // or newer installations findVisualStudio2017OrNewer: function findVisualStudio2017OrNewer (cb) { - var ps = path.join(process.env.SystemRoot, 'System32', + const ps = path.join(process.env.SystemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe') - var csFile = path.join(__dirname, 'Find-VisualStudio.cs') - var psArgs = [ + const csFile = path.join(__dirname, 'Find-VisualStudio.cs') + const psArgs = [ '-ExecutionPolicy', 'Unrestricted', '-NoProfile', @@ -137,7 +137,7 @@ VisualStudioFinder.prototype = { ] this.log.silly('Running', ps, psArgs) - var child = execFile(ps, psArgs, { encoding: 'utf8' }, + const child = execFile(ps, psArgs, { encoding: 'utf8' }, (err, stdout, stderr) => { this.parseData(err, stdout, stderr, cb) }) @@ -160,7 +160,7 @@ VisualStudioFinder.prototype = { return failPowershell() } - var vsInfo + let vsInfo try { vsInfo = JSON.parse(stdout) } catch (e) { @@ -177,7 +177,7 @@ VisualStudioFinder.prototype = { vsInfo = vsInfo.map((info) => { this.log.silly(`processing installation: "${info.path}"`) info.path = path.resolve(info.path) - var ret = this.getVersionInfo(info) + const ret = this.getVersionInfo(info) ret.path = info.path ret.msBuild = this.getMSBuild(info, ret.versionYear) ret.toolset = this.getToolset(info, ret.versionYear) @@ -198,7 +198,7 @@ VisualStudioFinder.prototype = { // Sort to place newer versions first vsInfo.sort((a, b) => b.versionYear - a.versionYear) - for (var i = 0; i < vsInfo.length; ++i) { + for (let i = 0; i < vsInfo.length; ++i) { const info = vsInfo[i] this.addLog(`checking VS${info.versionYear} (${info.version}) found ` + `at:\n"${info.path}"`) @@ -244,7 +244,7 @@ VisualStudioFinder.prototype = { return {} } this.log.silly('- version match = %j', match) - var ret = { + const ret = { version: info.version, versionMajor: parseInt(match[1], 10), versionMinor: parseInt(match[2], 10) @@ -257,22 +257,42 @@ VisualStudioFinder.prototype = { ret.versionYear = 2019 return ret } + if (ret.versionMajor === 17) { + ret.versionYear = 2022 + return ret + } this.log.silly('- unsupported version:', ret.versionMajor) return {} }, + msBuildPathExists: function msBuildPathExists (path) { + return fs.existsSync(path) + }, + // Helper - process MSBuild information getMSBuild: function getMSBuild (info, versionYear) { const pkg = 'Microsoft.VisualStudio.VC.MSBuild.Base' + const msbuildPath = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'MSBuild.exe') + const msbuildPathArm64 = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'arm64', 'MSBuild.exe') if (info.packages.indexOf(pkg) !== -1) { this.log.silly('- found VC.MSBuild.Base') if (versionYear === 2017) { return path.join(info.path, 'MSBuild', '15.0', 'Bin', 'MSBuild.exe') } if (versionYear === 2019) { - return path.join(info.path, 'MSBuild', 'Current', 'Bin', 'MSBuild.exe') + return msbuildPath } } + /** + * Visual Studio 2022 doesn't have the MSBuild package. + * Support for compiling _on_ ARM64 was added in MSVC 14.32.31326, + * so let's leverage it if the user has an ARM64 device. + */ + if (process.arch === 'arm64' && this.msBuildPathExists(msbuildPathArm64)) { + return msbuildPathArm64 + } else if (this.msBuildPathExists(msbuildPath)) { + return msbuildPath + } return null }, @@ -293,6 +313,8 @@ VisualStudioFinder.prototype = { return 'v141' } else if (versionYear === 2019) { return 'v142' + } else if (versionYear === 2022) { + return 'v143' } this.log.silly('- invalid versionYear:', versionYear) return null @@ -302,29 +324,30 @@ VisualStudioFinder.prototype = { getSDK: function getSDK (info) { const win8SDK = 'Microsoft.VisualStudio.Component.Windows81SDK' const win10SDKPrefix = 'Microsoft.VisualStudio.Component.Windows10SDK.' + const win11SDKPrefix = 'Microsoft.VisualStudio.Component.Windows11SDK.' - var Win10SDKVer = 0 + let Win10or11SDKVer = 0 info.packages.forEach((pkg) => { - if (!pkg.startsWith(win10SDKPrefix)) { + if (!pkg.startsWith(win10SDKPrefix) && !pkg.startsWith(win11SDKPrefix)) { return } const parts = pkg.split('.') if (parts.length > 5 && parts[5] !== 'Desktop') { - this.log.silly('- ignoring non-Desktop Win10SDK:', pkg) + this.log.silly('- ignoring non-Desktop Win10/11SDK:', pkg) return } const foundSdkVer = parseInt(parts[4], 10) if (isNaN(foundSdkVer)) { // Microsoft.VisualStudio.Component.Windows10SDK.IpOverUsb - this.log.silly('- failed to parse Win10SDK number:', pkg) + this.log.silly('- failed to parse Win10/11SDK number:', pkg) return } - this.log.silly('- found Win10SDK:', foundSdkVer) - Win10SDKVer = Math.max(Win10SDKVer, foundSdkVer) + this.log.silly('- found Win10/11SDK:', foundSdkVer) + Win10or11SDKVer = Math.max(Win10or11SDKVer, foundSdkVer) }) - if (Win10SDKVer !== 0) { - return `10.0.${Win10SDKVer}.0` + if (Win10or11SDKVer !== 0) { + return `10.0.${Win10or11SDKVer}.0` } else if (info.packages.indexOf(win8SDK) !== -1) { this.log.silly('- found Win8SDK') return '8.1' @@ -334,6 +357,11 @@ VisualStudioFinder.prototype = { // Find an installation of Visual Studio 2015 to use findVisualStudio2015: function findVisualStudio2015 (cb) { + if (this.nodeSemver.major >= 19) { + this.addLog( + 'not looking for VS2015 as it is only supported up to Node.js 18') + return cb(null) + } return this.findOldVS({ version: '14.0', versionMajor: 14, @@ -399,7 +427,7 @@ VisualStudioFinder.prototype = { }) }, - // After finding a usable version of Visual Stuido: + // After finding a usable version of Visual Studio: // - add it to validVersions to be displayed at the end if a specific // version was requested and not found; // - check if this is the version that was requested. @@ -429,6 +457,6 @@ VisualStudioFinder.prototype = { module.exports = findVisualStudio module.exports.test = { - VisualStudioFinder: VisualStudioFinder, - findVisualStudio: findVisualStudio + VisualStudioFinder, + findVisualStudio } diff --git a/lib/install.js b/lib/install.js index f9fa2b34bd..7ac34d2b83 100644 --- a/lib/install.js +++ b/lib/install.js @@ -2,57 +2,50 @@ const fs = require('graceful-fs') const os = require('os') +const { backOff } = require('exponential-backoff') +const rm = require('rimraf') const tar = require('tar') const path = require('path') +const util = require('util') +const stream = require('stream') const crypto = require('crypto') -const log = require('npmlog') +const log = require('./log') const semver = require('semver') -const request = require('request') +const fetch = require('make-fetch-happen') const processRelease = require('./process-release') const win = process.platform === 'win32' -const getProxyFromURI = require('./proxy') +const streamPipeline = util.promisify(stream.pipeline) -function install (fs, gyp, argv, callback) { - var release = processRelease(argv, gyp, process.version, process.release) +/** + * @param {typeof import('graceful-fs')} fs + */ - // ensure no double-callbacks happen - function cb (err) { - if (cb.done) { - return - } - cb.done = true - if (err) { - log.warn('install', 'got an error, rolling back install') - // roll-back the install if anything went wrong - gyp.commands.remove([release.versionDir], function () { - callback(err) - }) - } else { - callback(null, release.version) - } - } +async function install (fs, gyp, argv) { + const release = processRelease(argv, gyp, process.version, process.release) + // Detecting target_arch based on logic from create-cnfig-gyp.js. Used on Windows only. + const arch = win ? (gyp.opts.target_arch || gyp.opts.arch || process.arch || 'ia32') : '' + // Used to prevent downloading tarball if only new node.lib is required on Windows. + let shouldDownloadTarball = true // Determine which node dev files version we are installing log.verbose('install', 'input version string %j', release.version) if (!release.semver) { // could not parse the version string with semver - return callback(new Error('Invalid version number: ' + release.version)) + throw new Error('Invalid version number: ' + release.version) } if (semver.lt(release.version, '0.8.0')) { - return callback(new Error('Minimum target version is `0.8.0` or greater. Got: ' + release.version)) + throw new Error('Minimum target version is `0.8.0` or greater. Got: ' + release.version) } // 0.x.y-pre versions are not published yet and cannot be installed. Bail. if (release.semver.prerelease[0] === 'pre') { log.verbose('detected "pre" node version', release.version) - if (gyp.opts.nodedir) { - log.verbose('--nodedir flag was passed; skipping install', gyp.opts.nodedir) - callback() - } else { - callback(new Error('"pre" versions of node cannot be installed, use the --nodedir flag instead')) + if (!gyp.opts.nodedir) { + throw new Error('"pre" versions of node cannot be installed, use the --nodedir flag instead') } + log.verbose('--nodedir flag was passed; skipping install', gyp.opts.nodedir) return } @@ -60,296 +53,301 @@ function install (fs, gyp, argv, callback) { log.verbose('install', 'installing version: %s', release.versionDir) // the directory where the dev files will be installed - var devDir = path.resolve(gyp.devDir, release.versionDir) + const devDir = path.resolve(gyp.devDir, release.versionDir) // If '--ensure' was passed, then don't *always* install the version; // check if it is already installed, and only install when needed if (gyp.opts.ensure) { log.verbose('install', '--ensure was passed, so won\'t reinstall if already installed') - fs.stat(devDir, function (err) { - if (err) { + try { + await fs.promises.stat(devDir) + } catch (err) { + if (err.code === 'ENOENT') { + log.verbose('install', 'version not already installed, continuing with install', release.version) + try { + return await go() + } catch (err) { + return rollback(err) + } + } else if (err.code === 'EACCES') { + return eaccesFallback(err) + } + throw err + } + log.verbose('install', 'version is already installed, need to check "installVersion"') + const installVersionFile = path.resolve(devDir, 'installVersion') + let installVersion = 0 + try { + const ver = await fs.promises.readFile(installVersionFile, 'ascii') + installVersion = parseInt(ver, 10) || 0 + } catch (err) { + if (err.code !== 'ENOENT') { + throw err + } + } + log.verbose('got "installVersion"', installVersion) + log.verbose('needs "installVersion"', gyp.package.installVersion) + if (installVersion < gyp.package.installVersion) { + log.verbose('install', 'version is no good; reinstalling') + try { + return await go() + } catch (err) { + return rollback(err) + } + } + log.verbose('install', 'version is good') + if (win) { + log.verbose('on Windows; need to check node.lib') + const nodeLibPath = path.resolve(devDir, arch, 'node.lib') + try { + await fs.promises.stat(nodeLibPath) + } catch (err) { if (err.code === 'ENOENT') { - log.verbose('install', 'version not already installed, continuing with install', release.version) - go() + log.verbose('install', `version not already installed for ${arch}, continuing with install`, release.version) + try { + shouldDownloadTarball = false + return await go() + } catch (err) { + return rollback(err) + } } else if (err.code === 'EACCES') { - eaccesFallback(err) - } else { - cb(err) + return eaccesFallback(err) } - return + throw err } - log.verbose('install', 'version is already installed, need to check "installVersion"') - var installVersionFile = path.resolve(devDir, 'installVersion') - fs.readFile(installVersionFile, 'ascii', function (err, ver) { - if (err && err.code !== 'ENOENT') { - return cb(err) - } - var installVersion = parseInt(ver, 10) || 0 - log.verbose('got "installVersion"', installVersion) - log.verbose('needs "installVersion"', gyp.package.installVersion) - if (installVersion < gyp.package.installVersion) { - log.verbose('install', 'version is no good; reinstalling') - go() - } else { - log.verbose('install', 'version is good') - cb() - } - }) - }) + } } else { - go() + try { + return await go() + } catch (err) { + return rollback(err) + } } - function getContentSha (res, callback) { - var shasum = crypto.createHash('sha256') - res.on('data', function (chunk) { - shasum.update(chunk) - }).on('end', function () { - callback(null, shasum.digest('hex')) - }) + async function copyDirectory (src, dest) { + try { + await fs.promises.stat(src) + } catch { + throw new Error(`Missing source directory for copy: ${src}`) + } + await fs.promises.mkdir(dest, { recursive: true }) + const entries = await fs.promises.readdir(src, { withFileTypes: true }) + for (const entry of entries) { + if (entry.isDirectory()) { + await copyDirectory(path.join(src, entry.name), path.join(dest, entry.name)) + } else if (entry.isFile()) { + // with parallel installs, copying files may cause file errors on + // Windows so use an exponential backoff to resolve collisions + await backOff(async () => { + try { + await fs.promises.copyFile(path.join(src, entry.name), path.join(dest, entry.name)) + } catch (err) { + // if ensure, check if file already exists and that's good enough + if (gyp.opts.ensure && err.code === 'EBUSY') { + try { + await fs.promises.stat(path.join(dest, entry.name)) + return + } catch {} + } + throw err + } + }) + } else { + throw new Error('Unexpected file directory entry type') + } + } } - function go () { - log.verbose('ensuring nodedir is created', devDir) + async function go () { + log.verbose('ensuring devDir is created', devDir) // first create the dir for the node dev files - fs.mkdir(devDir, { recursive: true }, function (err, created) { - if (err) { - if (err.code === 'EACCES') { - eaccesFallback(err) - } else { - cb(err) - } - return - } + try { + const created = await fs.promises.mkdir(devDir, { recursive: true }) if (created) { - log.verbose('created nodedir', created) + log.verbose('created devDir', created) } - - // now download the node tarball - var tarPath = gyp.opts.tarball - var badDownload = false - var extractCount = 0 - var contentShasums = {} - var expectShasums = {} - - // checks if a file to be extracted from the tarball is valid. - // only .h header files and the gyp files get extracted - function isValid (path) { - var isValid = valid(path) - if (isValid) { - log.verbose('extracted file from tarball', path) - extractCount++ - } else { - // invalid - log.silly('ignoring from tarball', path) - } - return isValid + } catch (err) { + if (err.code === 'EACCES') { + return eaccesFallback(err) } - // download the tarball and extract! - if (tarPath) { - return tar.extract({ - file: tarPath, - strip: 1, - filter: isValid, - cwd: devDir - }).then(afterTarball, cb) - } + throw err + } - try { - var req = download(gyp, process.env, release.tarballUrl) - } catch (e) { - return cb(e) + // now download the node tarball + const tarPath = gyp.opts.tarball + let extractErrors = false + let extractCount = 0 + const contentShasums = {} + const expectShasums = {} + + // checks if a file to be extracted from the tarball is valid. + // only .h header files and the gyp files get extracted + function isValid (path) { + const isValid = valid(path) + if (isValid) { + log.verbose('extracted file from tarball', path) + extractCount++ + } else { + // invalid + log.silly('ignoring from tarball', path) } + return isValid + } - // something went wrong downloading the tarball? - req.on('error', function (err) { - if (err.code === 'ENOTFOUND') { - return cb(new Error('This is most likely not a problem with node-gyp or the package itself and\n' + - 'is related to network connectivity. In most cases you are behind a proxy or have bad \n' + - 'network settings.')) - } - badDownload = true - cb(err) - }) + function onwarn (code, message) { + extractErrors = true + log.error('error while extracting tarball', code, message) + } - req.on('close', function () { - if (extractCount === 0) { - cb(new Error('Connection closed while downloading tarball file')) - } - }) + // download the tarball and extract! + // Ommited on Windows if only new node.lib is required - req.on('response', function (res) { - if (res.statusCode !== 200) { - badDownload = true - cb(new Error(res.statusCode + ' response downloading ' + release.tarballUrl)) - return - } - // content checksum - getContentSha(res, function (_, checksum) { - var filename = path.basename(release.tarballUrl).trim() - contentShasums[filename] = checksum - log.verbose('content checksum', filename, checksum) - }) - - // start unzipping and untaring - res.pipe(tar.extract({ - strip: 1, - cwd: devDir, - filter: isValid - }).on('close', afterTarball).on('error', cb)) - }) - - // invoked after the tarball has finished being extracted - function afterTarball () { - if (badDownload) { - return - } - if (extractCount === 0) { - return cb(new Error('There was a fatal problem while downloading/extracting the tarball')) - } - log.verbose('tarball', 'done parsing tarball') - var async = 0 + // on Windows there can be file errors from tar if parallel installs + // are happening (not uncommon with multiple native modules) so + // extract the tarball to a temp directory first and then copy over + const tarExtractDir = win ? await fs.promises.mkdtemp(path.join(os.tmpdir(), 'node-gyp-tmp-')) : devDir - if (win) { - // need to download node.lib - async++ - downloadNodeLib(deref) - } + try { + if (shouldDownloadTarball) { + if (tarPath) { + await tar.extract({ + file: tarPath, + strip: 1, + filter: isValid, + onwarn, + cwd: tarExtractDir + }) + } else { + try { + const res = await download(gyp, release.tarballUrl) - // write the "installVersion" file - async++ - var installVersionPath = path.resolve(devDir, 'installVersion') - fs.writeFile(installVersionPath, gyp.package.installVersion + '\n', deref) + if (res.status !== 200) { + throw new Error(`${res.status} response downloading ${release.tarballUrl}`) + } - // Only download SHASUMS.txt if we downloaded something in need of SHA verification - if (!tarPath || win) { - // download SHASUMS.txt - async++ - downloadShasums(deref) + await streamPipeline( + res.body, + // content checksum + new ShaSum((_, checksum) => { + const filename = path.basename(release.tarballUrl).trim() + contentShasums[filename] = checksum + log.verbose('content checksum', filename, checksum) + }), + tar.extract({ + strip: 1, + cwd: tarExtractDir, + filter: isValid, + onwarn + }) + ) + } catch (err) { + // something went wrong downloading the tarball? + if (err.code === 'ENOTFOUND') { + throw new Error('This is most likely not a problem with node-gyp or the package itself and\n' + + 'is related to network connectivity. In most cases you are behind a proxy or have bad \n' + + 'network settings.') + } + throw err + } } - if (async === 0) { - // no async tasks required - cb() + // invoked after the tarball has finished being extracted + if (extractErrors || extractCount === 0) { + throw new Error('There was a fatal problem while downloading/extracting the tarball') } - function deref (err) { - if (err) { - return cb(err) - } + log.verbose('tarball', 'done parsing tarball') + } - async-- - if (!async) { - log.verbose('download contents checksum', JSON.stringify(contentShasums)) - // check content shasums - for (var k in contentShasums) { - log.verbose('validating download checksum for ' + k, '(%s == %s)', contentShasums[k], expectShasums[k]) - if (contentShasums[k] !== expectShasums[k]) { - cb(new Error(k + ' local checksum ' + contentShasums[k] + ' not match remote ' + expectShasums[k])) - return - } - } - cb() - } + const installVersionPath = path.resolve(tarExtractDir, 'installVersion') + await Promise.all([ + // need to download node.lib + ...(win ? [downloadNodeLib()] : []), + // write the "installVersion" file + fs.promises.writeFile(installVersionPath, gyp.package.installVersion + '\n'), + // Only download SHASUMS.txt if we downloaded something in need of SHA verification + ...(!tarPath || win ? [downloadShasums()] : []) + ]) + + log.verbose('download contents checksum', JSON.stringify(contentShasums)) + // check content shasums + for (const k in contentShasums) { + log.verbose('validating download checksum for ' + k, '(%s == %s)', contentShasums[k], expectShasums[k]) + if (contentShasums[k] !== expectShasums[k]) { + throw new Error(k + ' local checksum ' + contentShasums[k] + ' not match remote ' + expectShasums[k]) } } - function downloadShasums (done) { - log.verbose('check download content checksum, need to download `SHASUMS256.txt`...') - log.verbose('checksum url', release.shasumsUrl) + // copy over the files from the temp tarball extract directory to devDir + if (tarExtractDir !== devDir) { + await copyDirectory(tarExtractDir, devDir) + } + } finally { + if (tarExtractDir !== devDir) { try { - var req = download(gyp, process.env, release.shasumsUrl) - } catch (e) { - return cb(e) + // try to cleanup temp dir + await util.promisify(rm)(tarExtractDir) + } catch { + log.warn('failed to clean up temp tarball extract directory') } + } + } - req.on('error', done) - req.on('response', function (res) { - if (res.statusCode !== 200) { - done(new Error(res.statusCode + ' status code downloading checksum')) - return - } + async function downloadShasums () { + log.verbose('check download content checksum, need to download `SHASUMS256.txt`...') + log.verbose('checksum url', release.shasumsUrl) - var chunks = [] - res.on('data', function (chunk) { - chunks.push(chunk) - }) - res.on('end', function () { - var lines = Buffer.concat(chunks).toString().trim().split('\n') - lines.forEach(function (line) { - var items = line.trim().split(/\s+/) - if (items.length !== 2) { - return - } + const res = await download(gyp, release.shasumsUrl) - // 0035d18e2dcf9aad669b1c7c07319e17abfe3762 ./node-v0.11.4.tar.gz - var name = items[1].replace(/^\.\//, '') - expectShasums[name] = items[0] - }) + if (res.status !== 200) { + throw new Error(`${res.status} status code downloading checksum`) + } - log.verbose('checksum data', JSON.stringify(expectShasums)) - done() - }) - }) + for (const line of (await res.text()).trim().split('\n')) { + const items = line.trim().split(/\s+/) + if (items.length !== 2) { + return + } + + // 0035d18e2dcf9aad669b1c7c07319e17abfe3762 ./node-v0.11.4.tar.gz + const name = items[1].replace(/^\.\//, '') + expectShasums[name] = items[0] } - function downloadNodeLib (done) { - log.verbose('on Windows; need to download `' + release.name + '.lib`...') - var archs = ['ia32', 'x64', 'arm64'] - var async = archs.length - archs.forEach(function (arch) { - var dir = path.resolve(devDir, arch) - var targetLibPath = path.resolve(dir, release.name + '.lib') - var libUrl = release[arch].libUrl - var libPath = release[arch].libPath - var name = arch + ' ' + release.name + '.lib' - log.verbose(name, 'dir', dir) - log.verbose(name, 'url', libUrl) - - fs.mkdir(dir, { recursive: true }, function (err) { - if (err) { - return done(err) - } - log.verbose('streaming', name, 'to:', targetLibPath) + log.verbose('checksum data', JSON.stringify(expectShasums)) + } - try { - var req = download(gyp, process.env, libUrl, cb) - } catch (e) { - return cb(e) - } + async function downloadNodeLib () { + log.verbose('on Windows; need to download `' + release.name + '.lib`...') + const dir = path.resolve(tarExtractDir, arch) + const targetLibPath = path.resolve(dir, release.name + '.lib') + const { libUrl, libPath } = release[arch] + const name = `${arch} ${release.name}.lib` + log.verbose(name, 'dir', dir) + log.verbose(name, 'url', libUrl) - req.on('error', done) - req.on('response', function (res) { - if (res.statusCode === 403 || res.statusCode === 404) { - if (arch === 'arm64') { - // Arm64 is a newer platform on Windows and not all node distributions provide it. - log.verbose(`${name} was not found in ${libUrl}`) - } else { - log.warn(`${name} was not found in ${libUrl}`) - } - return - } else if (res.statusCode !== 200) { - done(new Error(res.statusCode + ' status code downloading ' + name)) - return - } + await fs.promises.mkdir(dir, { recursive: true }) + log.verbose('streaming', name, 'to:', targetLibPath) - getContentSha(res, function (_, checksum) { - contentShasums[libPath] = checksum - log.verbose('content checksum', libPath, checksum) - }) + const res = await download(gyp, libUrl) - var ws = fs.createWriteStream(targetLibPath) - ws.on('error', cb) - req.pipe(ws) - }) - req.on('end', function () { --async || done() }) - }) - }) - } // downloadNodeLib() - }) // mkdir() + // Since only required node.lib is downloaded throw error if it is not fetched + if (res.status !== 200) { + throw new Error(`${res.status} status code downloading ${name}`) + } + + return streamPipeline( + res.body, + new ShaSum((_, checksum) => { + contentShasums[libPath] = checksum + log.verbose('content checksum', libPath, checksum) + }), + fs.createWriteStream(targetLibPath) + ) + } // downloadNodeLib() } // go() /** @@ -358,10 +356,17 @@ function install (fs, gyp, argv, callback) { function valid (file) { // header files - var extname = path.extname(file) + const extname = path.extname(file) return extname === '.h' || extname === '.gypi' } + async function rollback (err) { + log.warn('install', 'got an error, rolling back install') + // roll-back the install if anything went wrong + await util.promisify(gyp.commands.remove)([release.versionDir]) + throw err + } + /** * The EACCES fallback is a workaround for npm's `sudo` behavior, where * it drops the permissions before invoking any child processes (like @@ -371,14 +376,14 @@ function install (fs, gyp, argv, callback) { * the compilation will succeed... */ - function eaccesFallback (err) { - var noretry = '--node_gyp_internal_noretry' + async function eaccesFallback (err) { + const noretry = '--node_gyp_internal_noretry' if (argv.indexOf(noretry) !== -1) { - return cb(err) + throw err } - var tmpdir = os.tmpdir() + const tmpdir = os.tmpdir() gyp.devDir = path.resolve(tmpdir, '.node-gyp') - var userString = '' + let userString = '' try { // os.userInfo can fail on some systems, it's not critical here userString = ` ("${os.userInfo().username}")` @@ -389,59 +394,65 @@ function install (fs, gyp, argv, callback) { log.verbose('tmpdir == cwd', 'automatically will remove dev files after to save disk space') gyp.todo.push({ name: 'remove', args: argv }) } - gyp.commands.install([noretry].concat(argv), cb) + return util.promisify(gyp.commands.install)([noretry].concat(argv)) } } -function download (gyp, env, url) { +class ShaSum extends stream.Transform { + constructor (callback) { + super() + this._callback = callback + this._digester = crypto.createHash('sha256') + } + + _transform (chunk, _, callback) { + this._digester.update(chunk) + callback(null, chunk) + } + + _flush (callback) { + this._callback(null, this._digester.digest('hex')) + callback() + } +} + +async function download (gyp, url) { log.http('GET', url) - var requestOpts = { - uri: url, + const requestOpts = { headers: { - 'User-Agent': 'node-gyp v' + gyp.version + ' (node ' + process.version + ')', + 'User-Agent': `node-gyp v${gyp.version} (node ${process.version})`, Connection: 'keep-alive' - } + }, + proxy: gyp.opts.proxy, + noProxy: gyp.opts.noproxy } - var cafile = gyp.opts.cafile + const cafile = gyp.opts.cafile if (cafile) { - requestOpts.ca = readCAFile(cafile) - } - - // basic support for a proxy server - var proxyUrl = getProxyFromURI(gyp, env, url) - if (proxyUrl) { - if (/^https?:\/\//i.test(proxyUrl)) { - log.verbose('download', 'using proxy url: "%s"', proxyUrl) - requestOpts.proxy = proxyUrl - } else { - log.warn('download', 'ignoring invalid "proxy" config setting: "%s"', proxyUrl) - } + requestOpts.ca = await readCAFile(cafile) } - var req = request(requestOpts) - req.on('response', function (res) { - log.http(res.statusCode, url) - }) + const res = await fetch(url, requestOpts) + log.http(res.status, res.url) - return req + return res } -function readCAFile (filename) { +async function readCAFile (filename) { // The CA file can contain multiple certificates so split on certificate // boundaries. [\S\s]*? is used to match everything including newlines. - var ca = fs.readFileSync(filename, 'utf8') - var re = /(-----BEGIN CERTIFICATE-----[\S\s]*?-----END CERTIFICATE-----)/g + const ca = await fs.promises.readFile(filename, 'utf8') + const re = /(-----BEGIN CERTIFICATE-----[\S\s]*?-----END CERTIFICATE-----)/g return ca.match(re) } module.exports = function (gyp, argv, callback) { - return install(fs, gyp, argv, callback) + install(fs, gyp, argv).then(callback.bind(undefined, null), callback) } module.exports.test = { - download: download, - install: install, - readCAFile: readCAFile + download, + install, + readCAFile } module.exports.usage = 'Install node development files for the specified node version.' diff --git a/lib/list.js b/lib/list.js index 405ebc0d88..d93370018f 100644 --- a/lib/list.js +++ b/lib/list.js @@ -1,10 +1,10 @@ 'use strict' const fs = require('graceful-fs') -const log = require('npmlog') +const log = require('./log') function list (gyp, args, callback) { - var devDir = gyp.devDir + const devDir = gyp.devDir log.verbose('list', 'using node-gyp dir:', devDir) fs.readdir(devDir, onreaddir) diff --git a/lib/log.js b/lib/log.js new file mode 100644 index 0000000000..47fa8a3372 --- /dev/null +++ b/lib/log.js @@ -0,0 +1,165 @@ +'use strict' + +const procLog = require('proc-log') +const { format } = require('util') + +// helper to emit log messages with a predefined prefix +const logLevels = Object.keys(procLog).filter((k) => typeof procLog[k] === 'function') +const withPrefix = (prefix) => logLevels.reduce((acc, level) => { + acc[level] = (...args) => procLog[level](prefix, ...args) + return acc +}, {}) + +// very basic ansi color generator +const COLORS = { + wrap: (str, colors) => { + const codes = colors.filter(c => typeof c === 'number') + return `\x1b[${codes.join(';')}m${str}\x1b[0m` + }, + inverse: 7, + fg: { + black: 30, + red: 31, + green: 32, + yellow: 33, + blue: 34, + magenta: 35, + cyan: 36, + white: 37 + }, + bg: { + black: 40, + red: 41, + green: 42, + yellow: 43, + blue: 44, + magenta: 45, + cyan: 46, + white: 47 + } +} + +class Logger { + #buffer = [] + #paused = null + #level = null + #stream = null + + // ordered from loudest to quietest + #levels = [{ + id: 'silly', + display: 'sill', + style: { inverse: true } + }, { + id: 'verbose', + display: 'verb', + style: { fg: 'cyan', bg: 'black' } + }, { + id: 'info', + style: { fg: 'green' } + }, { + id: 'http', + style: { fg: 'green', bg: 'black' } + }, { + id: 'notice', + style: { fg: 'cyan', bg: 'black' } + }, { + id: 'warn', + display: 'WARN', + style: { fg: 'black', bg: 'yellow' } + }, { + id: 'error', + display: 'ERR!', + style: { fg: 'red', bg: 'black' } + }] + + constructor () { + process.on('log', (...args) => this.#onLog(...args)) + this.#levels = new Map(this.#levels.map((level, index) => [level.id, { ...level, index }])) + this.level = 'info' + this.stream = process.stderr + procLog.pause() + } + + get stream () { + return this.#stream + } + + set stream (stream) { + this.#stream = stream + } + + get level () { + return this.#levels.get(this.#level) ?? null + } + + set level (level) { + this.#level = this.#levels.get(level)?.id ?? null + } + + isVisible (level) { + return this.level?.index <= this.#levels.get(level)?.index ?? -1 + } + + #onLog (...args) { + const [level] = args + + if (level === 'pause') { + this.#paused = true + return + } + + if (level === 'resume') { + this.#paused = false + this.#buffer.forEach((b) => this.#log(...b)) + this.#buffer.length = 0 + return + } + + if (this.#paused) { + this.#buffer.push(args) + return + } + + this.#log(...args) + } + + #color (str, { fg, bg, inverse }) { + if (!this.#stream?.isTTY) { + return str + } + + return COLORS.wrap(str, [ + COLORS.fg[fg], + COLORS.bg[bg], + inverse && COLORS.inverse + ]) + } + + #log (levelId, msgPrefix, ...args) { + if (!this.isVisible(levelId) || typeof this.#stream?.write !== 'function') { + return + } + + const level = this.#levels.get(levelId) + + const prefixParts = [ + this.#color('gyp', { fg: 'white', bg: 'black' }), + this.#color(level.display ?? level.id, level.style) + ] + if (msgPrefix) { + prefixParts.push(this.#color(msgPrefix, { fg: 'magenta' })) + } + + const prefix = prefixParts.join(' ').trim() + ' ' + const lines = format(...args).split(/\r?\n/).map(l => prefix + l.trim()) + + this.#stream.write(lines.join('\n') + '\n') + } +} + +module.exports = { + logger: new Logger(), + withPrefix, + ...procLog +} diff --git a/lib/node-gyp.js b/lib/node-gyp.js index 81fc590919..392a0ecfa6 100644 --- a/lib/node-gyp.js +++ b/lib/node-gyp.js @@ -2,7 +2,7 @@ const path = require('path') const nopt = require('nopt') -const log = require('npmlog') +const log = require('./log') const childProcess = require('child_process') const EE = require('events').EventEmitter const inherits = require('util').inherits @@ -22,15 +22,12 @@ const aliases = { rm: 'remove' } -// differentiate node-gyp's logs from npm's -log.heading = 'gyp' - function gyp () { return new Gyp() } function Gyp () { - var self = this + const self = this this.devDir = '' this.commands = {} @@ -44,7 +41,7 @@ function Gyp () { } inherits(Gyp, EE) exports.Gyp = Gyp -var proto = Gyp.prototype +const proto = Gyp.prototype /** * Export the contents of the package.json. @@ -63,7 +60,7 @@ proto.configDefs = { debug: Boolean, // 'build' directory: String, // bin make: String, // 'build' - msvs_version: String, // 'configure' + 'msvs-version': String, // 'configure' ensure: Boolean, // 'install' solution: String, // 'build' (windows only) proxy: String, // 'install' @@ -75,7 +72,8 @@ proto.configDefs = { 'dist-url': String, // 'install' tarball: String, // 'install' jobs: String, // 'build' - thin: String // 'configure' + thin: String, // 'configure' + 'force-process-config': Boolean // 'configure' } /** @@ -107,7 +105,7 @@ proto.parseArgv = function parseOpts (argv) { this.opts = nopt(this.configDefs, this.shorthands, argv) this.argv = this.opts.argv.remain.slice() - var commands = this.todo = [] + const commands = this.todo = [] // create a copy of the argv array with aliases mapped argv = this.argv.map(function (arg) { @@ -121,7 +119,7 @@ proto.parseArgv = function parseOpts (argv) { // process the mapped args into "command" objects ("name" and "args" props) argv.slice().forEach(function (arg) { if (arg in this.commands) { - var args = argv.splice(0, argv.indexOf(arg)) + const args = argv.splice(0, argv.indexOf(arg)) argv.shift() if (commands.length > 0) { commands[commands.length - 1].args = args @@ -134,27 +132,31 @@ proto.parseArgv = function parseOpts (argv) { } // support for inheriting config env variables from npm - var npmConfigPrefix = 'npm_config_' + const npmConfigPrefix = 'npm_config_' Object.keys(process.env).forEach(function (name) { if (name.indexOf(npmConfigPrefix) !== 0) { return } - var val = process.env[name] + const val = process.env[name] if (name === npmConfigPrefix + 'loglevel') { - log.level = val + log.logger.level = val } else { // add the user-defined options to the config name = name.substring(npmConfigPrefix.length) // gyp@741b7f1 enters an infinite loop when it encounters // zero-length options so ensure those don't get through. if (name) { + // convert names like force_process_config to force-process-config + if (name.includes('_')) { + name = name.replace(/_/g, '-') + } this.opts[name] = val } } }, this) if (this.opts.loglevel) { - log.level = this.opts.loglevel + log.logger.level = this.opts.loglevel } log.resume() } @@ -170,7 +172,7 @@ proto.spawn = function spawn (command, args, opts) { if (!opts.silent && !opts.stdio) { opts.stdio = [0, 1, 2] } - var cp = childProcess.spawn(command, args, opts) + const cp = childProcess.spawn(command, args, opts) log.info('spawn', command) log.info('spawn args', args) return cp @@ -181,7 +183,7 @@ proto.spawn = function spawn (command, args, opts) { */ proto.usage = function usage () { - var str = [ + const str = [ '', ' Usage: node-gyp [options]', '', diff --git a/lib/process-release.js b/lib/process-release.js index 95b55e4426..c9a319dfad 100644 --- a/lib/process-release.js +++ b/lib/process-release.js @@ -1,11 +1,11 @@ -/* eslint-disable node/no-deprecated-api */ +/* eslint-disable n/no-deprecated-api */ 'use strict' const semver = require('semver') const url = require('url') const path = require('path') -const log = require('npmlog') +const log = require('./log') // versions where -headers.tar.gz started shipping const headersTarballRange = '>= 3.0.0 || ~0.12.10 || ~0.10.42' @@ -17,29 +17,28 @@ const bitsreV3 = /\/win-(x86|ia32|x64)\// // io.js v3.x.x shipped with "ia32" bu // file names. Inputs come from command-line switches (--target, --dist-url), // `process.version` and `process.release` where it exists. function processRelease (argv, gyp, defaultVersion, defaultRelease) { - var version = (semver.valid(argv[0]) && argv[0]) || gyp.opts.target || defaultVersion - var versionSemver = semver.parse(version) - var overrideDistUrl = gyp.opts['dist-url'] || gyp.opts.disturl - var isDefaultVersion - var isNamedForLegacyIojs - var name - var distBaseUrl - var baseUrl - var libUrl32 - var libUrl64 - var libUrlArm64 - var tarballUrl - var canGetHeaders + let version = (semver.valid(argv[0]) && argv[0]) || gyp.opts.target || defaultVersion + const versionSemver = semver.parse(version) + let overrideDistUrl = gyp.opts['dist-url'] || gyp.opts.disturl + let isNamedForLegacyIojs + let name + let distBaseUrl + let baseUrl + let libUrl32 + let libUrl64 + let libUrlArm64 + let tarballUrl + let canGetHeaders if (!versionSemver) { // not a valid semver string, nothing we can do - return { version: version } + return { version } } // flatten version into String version = versionSemver.version // defaultVersion should come from process.version so ought to be valid semver - isDefaultVersion = version === semver.parse(defaultVersion).version + const isDefaultVersion = version === semver.parse(defaultVersion).version // can't use process.release if we're using --target=x.y.z if (!isDefaultVersion) { @@ -101,11 +100,11 @@ function processRelease (argv, gyp, defaultVersion, defaultRelease) { } return { - version: version, + version, semver: versionSemver, - name: name, - baseUrl: baseUrl, - tarballUrl: tarballUrl, + name, + baseUrl, + tarballUrl, shasumsUrl: url.resolve(baseUrl, 'SHASUMS256.txt'), versionDir: (name !== 'node' ? name + '-' : '') + version, ia32: { @@ -128,8 +127,8 @@ function normalizePath (p) { } function resolveLibUrl (name, defaultUrl, arch, versionMajor) { - var base = url.resolve(defaultUrl, './') - var hasLibUrl = bitsre.test(defaultUrl) || (versionMajor === 3 && bitsreV3.test(defaultUrl)) + const base = url.resolve(defaultUrl, './') + const hasLibUrl = bitsre.test(defaultUrl) || (versionMajor === 3 && bitsreV3.test(defaultUrl)) if (!hasLibUrl) { // let's assume it's a baseUrl then diff --git a/lib/proxy.js b/lib/proxy.js deleted file mode 100644 index 92d9ed2f7f..0000000000 --- a/lib/proxy.js +++ /dev/null @@ -1,92 +0,0 @@ -'use strict' -// Taken from https://github.com/request/request/blob/212570b/lib/getProxyFromURI.js - -const url = require('url') - -function formatHostname (hostname) { - // canonicalize the hostname, so that 'oogle.com' won't match 'google.com' - return hostname.replace(/^\.*/, '.').toLowerCase() -} - -function parseNoProxyZone (zone) { - zone = zone.trim().toLowerCase() - - var zoneParts = zone.split(':', 2) - var zoneHost = formatHostname(zoneParts[0]) - var zonePort = zoneParts[1] - var hasPort = zone.indexOf(':') > -1 - - return { hostname: zoneHost, port: zonePort, hasPort: hasPort } -} - -function uriInNoProxy (uri, noProxy) { - var port = uri.port || (uri.protocol === 'https:' ? '443' : '80') - var hostname = formatHostname(uri.hostname) - var noProxyList = noProxy.split(',') - - // iterate through the noProxyList until it finds a match. - return noProxyList.map(parseNoProxyZone).some(function (noProxyZone) { - var isMatchedAt = hostname.indexOf(noProxyZone.hostname) - var hostnameMatched = ( - isMatchedAt > -1 && - (isMatchedAt === hostname.length - noProxyZone.hostname.length) - ) - - if (noProxyZone.hasPort) { - return (port === noProxyZone.port) && hostnameMatched - } - - return hostnameMatched - }) -} - -function getProxyFromURI (gyp, env, uri) { - // If a string URI/URL was given, parse it into a URL object - if (typeof uri === 'string') { - // eslint-disable-next-line - uri = url.parse(uri) - } - - // Decide the proper request proxy to use based on the request URI object and the - // environmental variables (NO_PROXY, HTTP_PROXY, etc.) - // respect NO_PROXY environment variables (see: https://lynx.invisible-island.net/lynx2.8.7/breakout/lynx_help/keystrokes/environments.html) - - var noProxy = gyp.opts.noproxy || env.NO_PROXY || env.no_proxy || env.npm_config_noproxy || '' - - // if the noProxy is a wildcard then return null - - if (noProxy === '*') { - return null - } - - // if the noProxy is not empty and the uri is found return null - - if (noProxy !== '' && uriInNoProxy(uri, noProxy)) { - return null - } - - // Check for HTTP or HTTPS Proxy in environment Else default to null - - if (uri.protocol === 'http:') { - return gyp.opts.proxy || - env.HTTP_PROXY || - env.http_proxy || - env.npm_config_proxy || null - } - - if (uri.protocol === 'https:') { - return gyp.opts.proxy || - env.HTTPS_PROXY || - env.https_proxy || - env.HTTP_PROXY || - env.http_proxy || - env.npm_config_proxy || null - } - - // if none of that works, return null - // (What uri protocol are you using then?) - - return null -} - -module.exports = getProxyFromURI diff --git a/lib/remove.js b/lib/remove.js index 8c945e5659..9561cb95e5 100644 --- a/lib/remove.js +++ b/lib/remove.js @@ -1,46 +1,45 @@ 'use strict' -const fs = require('fs') -const rm = require('rimraf') +const fs = require('fs/promises') const path = require('path') -const log = require('npmlog') +const log = require('./log') const semver = require('semver') -function remove (gyp, argv, callback) { - var devDir = gyp.devDir +async function remove (gyp, argv) { + const devDir = gyp.devDir log.verbose('remove', 'using node-gyp dir:', devDir) // get the user-specified version to remove - var version = argv[0] || gyp.opts.target + let version = argv[0] || gyp.opts.target log.verbose('remove', 'removing target version:', version) if (!version) { - return callback(new Error('You must specify a version number to remove. Ex: "' + process.version + '"')) + throw new Error('You must specify a version number to remove. Ex: "' + process.version + '"') } - var versionSemver = semver.parse(version) + const versionSemver = semver.parse(version) if (versionSemver) { // flatten the version Array into a String version = versionSemver.version } - var versionPath = path.resolve(gyp.devDir, version) + const versionPath = path.resolve(gyp.devDir, version) log.verbose('remove', 'removing development files for version:', version) // first check if its even installed - fs.stat(versionPath, function (err) { - if (err) { - if (err.code === 'ENOENT') { - callback(null, 'version was already uninstalled: ' + version) - } else { - callback(err) - } - return + try { + await fs.stat(versionPath) + } catch (err) { + if (err.code === 'ENOENT') { + return 'version was already uninstalled: ' + version } - // Go ahead and delete the dir - rm(versionPath, callback) - }) + throw err + } + + await fs.rm(versionPath, { recursive: true, force: true }) } -module.exports = exports = remove +module.exports = function (gyp, argv, callback) { + remove(gyp, argv).then(callback.bind(undefined, null), callback) +} module.exports.usage = 'Removes the node development files for the specified version' diff --git a/lib/util.js b/lib/util.js index 3e23c628e6..5950aa25b4 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,22 +1,9 @@ 'use strict' -const log = require('npmlog') +const log = require('./log') const execFile = require('child_process').execFile const path = require('path') -function logWithPrefix (log, prefix) { - function setPrefix (logFunction) { - return (...args) => logFunction.apply(null, [ prefix, ...args ]) // eslint-disable-line - } - return { - silly: setPrefix(log.silly), - verbose: setPrefix(log.verbose), - info: setPrefix(log.info), - warn: setPrefix(log.warn), - error: setPrefix(log.error) - } -} - function regGetValue (key, value, addOpts, cb) { const outReValue = value.replace(/\W/g, '.') const outRe = new RegExp(`^\\s+${outReValue}\\s+REG_\\w+\\s+(\\S.*)$`, 'im') @@ -45,7 +32,7 @@ function regGetValue (key, value, addOpts, cb) { } function regSearchKeys (keys, value, addOpts, cb) { - var i = 0 + let i = 0 const search = () => { log.silly('reg-search', 'looking for %j in %j', value, keys[i]) regGetValue(keys[i], value, addOpts, (err, res) => { @@ -58,7 +45,6 @@ function regSearchKeys (keys, value, addOpts, cb) { } module.exports = { - logWithPrefix: logWithPrefix, - regGetValue: regGetValue, - regSearchKeys: regSearchKeys + regGetValue, + regSearchKeys } diff --git a/macOS_Catalina.md b/macOS_Catalina.md deleted file mode 100644 index 4fe0f29b21..0000000000 --- a/macOS_Catalina.md +++ /dev/null @@ -1,104 +0,0 @@ -# Installation notes for macOS Catalina (v10.15) - -_This document specifically refers to upgrades from previous versions of macOS to Catalina (10.15). It should be removed from the source repository when Catalina ceases to be the latest macOS version or when future Catalina versions no longer raise these issues._ - -**Both upgrading to macOS Catalina and running a Software Update in Catalina may cause normal `node-gyp` installations to fail. This might manifest as the following error during `npm install`:** - -```console -gyp: No Xcode or CLT version detected! -``` - -## node-gyp v7 - -The newest release of `node-gyp` should solve this problem. If you are using `node-gyp` directly then you should be able to install v7 and use it as-is. - -If you need to use `node-gyp` from within `npm` (e.g. through `npm install`), you will have to install `node-gyp` (either globally with `-g` or to a predictable location) and tell `npm` where the new version is. Either use: - -* `npm config set node_gyp `; or -* run `npm` with an environment variable prefix: `npm_config_node_gyp= npm install` - -Where "path to node-gyp" is to the `node-gyp` executable which may be a symlink in your global bin directory (e.g. `/usr/local/bin/node-gyp`), or a path to the `node-gyp` installation directory and the `bin/node-gyp.js` file within it (e.g. `/usr/local/lib/node_modules/node-gyp/bin/node-gyp.js`). - -**If you use `npm config set` to change your global `node_gyp` you are responsible for keeping it up to date and can't rely on `npm` to give you a newer version when available.** Use `npm config delete node_gyp` to unset this configuration option. - -## Fixing Catalina for older versions of `node-gyp` - -### Is my Mac running macOS Catalina? -Let's first make sure that your Mac is running Catalina: -``` -% sw_vers - ProductName: Mac OS X - ProductVersion: 10.15 - BuildVersion: 19A602 -``` -If `ProductVersion` is less then `10.15` then this document is not for you. Normal install docs for `node-gyp` on macOS can be found at https://github.com/nodejs/node-gyp#on-macos - - -### The acid test -To see if `Xcode Command Line Tools` is installed in a way that will work with `node-gyp`, run: -``` -curl -sL https://github.com/nodejs/node-gyp/raw/master/macOS_Catalina_acid_test.sh | bash -``` - -If test succeeded, _you are done_! You should be ready to [install](https://github.com/nodejs/node-gyp#installation) `node-gyp`. - -If test failed, there is a problem with your Xcode Command Line Tools installation. [Continue to Solutions](#Solutions). - -### Solutions -There are three ways to install the Xcode libraries `node-gyp` needs on macOS. People running Catalina have had success with some but not others in a way that has been unpredictable. - -1. With the full Xcode (~7.6 GB download) from the `App Store` app. -2. With the _much_ smaller Xcode Command Line Tools via `xcode-select --install` -3. With the _much_ smaller Xcode Command Line Tools via manual download. **For people running the latest version of Catalina (10.15.2 at the time of this writing), this has worked when the other two solutions haven't.** - -### Installing `node-gyp` using the full Xcode -1. `xcodebuild -version` should show `Xcode 11.1` or later. - * If not, then install/upgrade Xcode from the App Store app. -2. Open the Xcode app and... - * Under __Preferences > Locations__ select the tools if their location is empty. - * Allow Xcode app to do an essential install of the most recent compiler tools. -3. Once all installations are _complete_, quit out of Xcode. -4. `sudo xcodebuild -license accept` # If you agree with the licensing terms. -5. `softwareupdate -l` # No listing is a good sign. - * If Xcode or Tools upgrades are listed, use "Software Upgrade" to install them. -6. `xcode-select -version` # Should return `xcode-select version 2370` or later. -7. `xcode-select -print-path` # Should return `/Applications/Xcode.app/Contents/Developer` -8. Try the [_acid test_ steps above](#The-acid-test) to see if your Mac is ready. -9. If the _acid test_ does _not_ pass then... -10. `sudo xcode-select --reset` # Enter root password. No output is normal. -11. Repeat step 7 above. Is the path different this time? Repeat the _acid test_. - -### Installing `node-gyp` using the Xcode Command Line Tools via `xcode-select --install` -1. If the _acid test_ has not succeeded, then try `xcode-select --install` -2. If the installation command returns `xcode-select: error: command line tools are already installed, use "Software Update" to install updates`, continue to [remove and reinstall](#i-did-all-that-and-the-acid-test-still-does-not-pass--) -3. Wait until the install process is _complete_. -4. `softwareupdate -l` # No listing is a good sign. - * If Xcode or Tools upgrades are listed, use "Software Update" to install them. -5. `xcode-select -version` # Should return `xcode-select version 2370` or later. -6. `xcode-select -print-path` # Should return `/Library/Developer/CommandLineTools` -7. Try the [_acid test_ steps above](#The-acid-test) to see if your Mac is ready. -8. If the _acid test_ does _not_ pass then... -9. `sudo xcode-select --reset` # Enter root password. No output is normal. -10. Repeat step 5 above. Is the path different this time? Repeat the _acid test_. - -### Installing `node-gyp` using the Xcode Command Line Tools via manual download -1. Download the appropriate version of the "Command Line Tools for Xcode" for your version of Catalina from . As of MacOS 10.15.5, that's [Command_Line_Tools_for_Xcode_11.5.dmg](https://download.developer.apple.com/Developer_Tools/Command_Line_Tools_for_Xcode_11.5/Command_Line_Tools_for_Xcode_11.5.dmg) -2. Install the package. -3. Run the [_acid test_ steps above](#The-acid-test). - -### I did all that and the acid test still does not pass :-( -1. `sudo rm -rf $(xcode-select -print-path)` # Enter root password. No output is normal. -2. `sudo rm -rf /Library/Developer/CommandLineTools` # Enter root password. -3. `sudo xcode-select --reset` -4. `xcode-select --install` -5. If the [_acid test_ steps above](#The-acid-test) still does _not_ pass then... -6. `npm explore npm -g -- npm install node-gyp@latest` -7. `npm explore npm -g -- npm explore npm-lifecycle -- npm install node-gyp@latest` -8. If the _acid test_ still does _not_ pass then... -9. Add a comment to https://github.com/nodejs/node-gyp/issues/1927 so we can improve. - -Lessons learned from: -* https://github.com/nodejs/node-gyp/issues/1779 -* https://github.com/nodejs/node-gyp/issues/1861 -* https://github.com/nodejs/node-gyp/issues/1927 and elsewhere -* Thanks to @rrrix for discovering Solution 3 diff --git a/package.json b/package.json index 8e256f0170..d861261002 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "bindings", "gyp" ], - "version": "7.1.2", - "installVersion": 9, + "version": "9.4.0", + "installVersion": 11, "author": "Nathan Rajlich (http://tootallnate.net)", "repository": { "type": "git", @@ -23,28 +23,28 @@ "main": "./lib/node-gyp.js", "dependencies": { "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" + "exponential-backoff": "^3.1.1", + "glob": "^8.0.3", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^11.0.3", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^3.0.0" }, "engines": { - "node": ">= 10.12.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "devDependencies": { "bindings": "^1.5.0", + "mocha": "^10.2.0", "nan": "^2.14.2", "require-inject": "^1.4.4", - "standard": "^14.3.4", - "tap": "^12.7.0" + "standard": "^17.0.0" }, "scripts": { "lint": "standard */*.js test/**/*.js", - "test": "npm run lint && tap --timeout=120 test/test-*" + "test": "npm run lint && mocha --timeout 15000 --reporter=test/reporter.js test/test-download.js test/test-*" } } diff --git a/test/fixtures/VS_2022_Community_workload.txt b/test/fixtures/VS_2022_Community_workload.txt new file mode 100644 index 0000000000..7cd20f8598 --- /dev/null +++ b/test/fixtures/VS_2022_Community_workload.txt @@ -0,0 +1,569 @@ +[ + { + "path": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community", + "version": "17.4.33213.308", + "packages": [ + "Microsoft.VisualStudio.Product.Community", + "Microsoft.VisualStudio.PackageGroup.LiveShare.VSCore", + "Microsoft.VisualStudio.LiveShare.VSCore", + "Microsoft.VisualStudio.Workload.NativeDesktop", + "Microsoft.VisualStudio.Component.VC.ASAN", + "Microsoft.VisualCpp.ASAN.X86", + "Microsoft.VC.14.34.17.4.ASAN.X86.base", + "Microsoft.VC.14.34.17.4.ASAN.X64.base", + "Microsoft.VC.14.34.17.4.ASAN.Headers.base", + "Microsoft.VisualStudio.VC.IDE.Project.Factories", + "Microsoft.VisualStudio.Component.VC.TestAdapterForGoogleTest", + "Microsoft.VisualStudio.VC.Ide.TestAdapterForGoogleTest", + "Microsoft.VisualStudio.Component.VC.TestAdapterForBoostTest", + "Microsoft.VisualStudio.VC.Ide.TestAdapterForBoostTest", + "Microsoft.VisualStudio.Component.VC.CMake.Project", + "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions.CMake", + "Microsoft.VisualStudio.VC.CMake", + "Microsoft.VisualStudio.VC.CMake.Project", + "Microsoft.VisualStudio.VC.CMake.Client", + "Microsoft.VisualStudio.VC.ExternalBuildFramework", + "Microsoft.VisualStudio.Component.VC.DiagnosticTools", + "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core", + "Microsoft.VisualStudio.PackageGroup.TestTools.Native", + "Microsoft.VisualStudio.Component.VC.Redist.14.Latest", + "Microsoft.VisualStudio.VC.Templates.UnitTest", + "Microsoft.VisualStudio.VC.UnitTest.Desktop.Build.Core", + "Microsoft.VisualStudio.TestTools.TestPlatform.V1.CPP", + "Microsoft.VisualStudio.VC.Templates.UnitTest.Resources", + "Microsoft.VisualStudio.VC.Templates.Desktop", + "Microsoft.VisualStudio.Component.Graphics", + "Microsoft.VisualStudio.Graphics.Viewers", + "Microsoft.VisualStudio.Graphics.Viewers.Resources", + "Microsoft.VisualStudio.Component.VC.ATL.ARM64", + "Microsoft.VisualCpp.ATL.ARM64", + "Microsoft.VC.14.34.17.4.ATL.ARM64.base", + "Microsoft.VisualStudio.Component.VC.ATL", + "Microsoft.VisualStudio.VC.Ide.ATL", + "Microsoft.VisualStudio.VC.Ide.ATL.Resources", + "Microsoft.VisualCpp.ATL.X86", + "Microsoft.VC.14.34.17.4.ATL.X86.base", + "Microsoft.VisualCpp.ATL.X64", + "Microsoft.VC.14.34.17.4.ATL.X64.base", + "Microsoft.VC.14.34.17.4.Props.ATLMFC", + "Microsoft.VisualCpp.ATL.Source", + "Microsoft.VC.14.34.17.4.ATL.Source.base", + "Microsoft.VisualCpp.ATL.Headers", + "Microsoft.VC.14.34.17.4.ATL.Headers.base", + "Microsoft.VC.14.34.17.4.Servicing.ATL", + "Microsoft.VisualStudio.Component.VC.Tools.ARM64", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM64.v143", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM64", + "Microsoft.VS.VC.vcvars.arm64.Shortcuts", + "Microsoft.VisualCpp.CA.Ext.Hostx64.TargetARM64", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.TargetARM64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.TargetARM64.Res.base", + "Microsoft.VisualCpp.CA.Ext.Hostx86.TargetARM64", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.TargetARM64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.TargetARM64.Res.base", + "Microsoft.VisualCpp.CA.Ext.HostARM64.TargetARM64", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.TargetARM64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.TargetARM64.Res.base", + "Microsoft.VisualCpp.Tools.Hostx86.Targetarm64", + "Microsoft.VC.14.34.17.4.Tools.Hostx86.Targetarm64.base", + "Microsoft.VC.14.34.17.4.Tools.HostX86.TargetARM64.Res.base", + "Microsoft.VisualCpp.Tools.HostARM64.TargetARM64", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetARM64.base", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetARM64.Res.base", + "Microsoft.VisualCpp.CRT.Redist.ARM64.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.Redist.ARM64.OneCore.Desktop.base", + "Microsoft.VisualCpp.CRT.Redist.ARM64", + "Microsoft.VC.14.34.17.4.CRT.Redist.ARM64.base", + "Microsoft.VisualCpp.CRT.ARM64.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.ARM64.OneCore.Desktop.base", + "Microsoft.VC.14.34.17.4.CRT.ARM64.OneCore.Desktop.debug.base", + "Microsoft.VisualCpp.CRT.ARM64.Store", + "Microsoft.VC.14.34.17.4.CRT.ARM64.Store.base", + "Microsoft.VisualCpp.CRT.ARM64.Desktop", + "Microsoft.VC.14.34.17.4.CRT.ARM64.Desktop.base", + "Microsoft.VC.14.34.17.4.CRT.ARM64.Desktop.debug.base", + "Microsoft.VisualStudio.PackageGroup.VC.Tools.x64.ARM64", + "Microsoft.VisualCpp.Tools.Core", + "Microsoft.VisualCpp.PGO.ARM64", + "Microsoft.VC.14.34.17.4.PGO.ARM64.base", + "Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetarm64", + "Microsoft.VC.14.34.17.4.Premium.Tools.Hostx86.Targetarm64.base", + "Microsoft.VC.14.34.17.4.Prem.HostX86.TargetARM64.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostX64.TargetARM64", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostX64.TargetARM64.base", + "Microsoft.VC.14.34.17.4.Prem.HostX64.TargetARM64.Res.base", + "Microsoft.VisualCpp.Premium.Tools.ARM64.Base", + "Microsoft.VC.14.34.17.4.Premium.Tools.ARM64.Base.base", + "Microsoft.VisualCpp.Tools.HostX64.TargetARM64", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetARM64.base", + "Microsoft.VC.14.34.17.4.Props.ARM64", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetARM64.Res.base", + "Microsoft.VisualStudio.Component.VC.Tools.ARM64EC", + "Microsoft.VisualStudio.Component.Windows11SDK.22621", + "Win11SDK_10.0.22621", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM64EC.v143", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM64EC", + "Microsoft.VisualCpp.CRT.ARM64EC.Store", + "Microsoft.VC.14.34.17.4.CRT.ARM64EC.Store.base", + "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "Microsoft.VisualCpp.CodeAnalysis.Extensions", + "Microsoft.VisualCpp.CA.Ext.HostARM64.Targetx64", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx64.Res.base", + "Microsoft.VisualCpp.CA.Ext.HostARM64.Targetx86", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx86.base", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx86.Res.base", + "Microsoft.VisualCpp.CA.Ext.Hostx86.Targetx64", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx64.Res.base", + "Microsoft.VisualCpp.CA.Ext.Hostx86.Targetx86", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx86.base", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx86.Res.base", + "Microsoft.VisualCpp.CA.Ext.Hostx64.Targetx64", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx64.Res.base", + "Microsoft.VisualCpp.CA.Ext.Hostx64.Targetx86", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx86.base", + "Microsoft.VC.14.34.17.4.Servicing.CAExtensions", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx86.Res.base", + "Microsoft.VisualCpp.Tools.HostX64.TargetX86", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX86.base", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX86.Res.base", + "Microsoft.VisualCpp.Tools.HostX64.TargetX64", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX64.base", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX64.Res.base", + "Microsoft.VisualCpp.Tools.HostARM64.TargetX86", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetX86.base", + "Microsoft.VisualCpp.RuntimeDebug.14", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetX86.Res.base", + "Microsoft.VisualCpp.Tools.HostARM64.TargetX64", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetX64.base", + "Microsoft.VisualCpp.RuntimeDebug.14.ARM64", + "Microsoft.VisualCpp.Redist.14.Latest", + "Microsoft.VisualCpp.Redist.14.Latest", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.Targetx64.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostX86.TargetX64.base", + "Microsoft.VC.14.34.17.4.Prem.Hostx86.Targetx64.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostX86.TargetX86.base", + "Microsoft.VC.14.34.17.4.Prem.HostX86.TargetX86.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostARM64.TargetX86", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostARM64.TargetX86.base", + "Microsoft.VC.14.34.17.4.Prem.HostARM64.TargetX86.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostARM64.TargetX64", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostARM64.TargetX64.base", + "Microsoft.VC.14.34.17.4.Prem.HostARM64.Targetx64.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostX64.TargetX86.base", + "Microsoft.VC.14.34.17.4.Prem.HostX64.TargetX86.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostX64.TargetX64.base", + "Microsoft.VC.14.34.17.4.Prem.HostX64.TargetX64.Res.base", + "Microsoft.VisualCpp.PGO.X86", + "Microsoft.VC.14.34.17.4.PGO.X86.base", + "Microsoft.VisualCpp.PGO.X64", + "Microsoft.VC.14.34.17.4.PGO.X64.base", + "Microsoft.VisualCpp.PGO.Headers", + "Microsoft.VC.14.34.17.4.PGO.Headers.base", + "Microsoft.VisualCpp.CRT.x86.Store", + "Microsoft.VC.14.34.17.4.CRT.x86.Store.base", + "Microsoft.VisualCpp.CRT.x86.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.x86.OneCore.Desktop.base", + "Microsoft.VisualCpp.CRT.x64.Store", + "Microsoft.VC.14.34.17.4.CRT.x64.Store.base", + "Microsoft.VisualCpp.CRT.x64.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.x64.OneCore.Desktop.base", + "Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.Redist.x86.OneCore.Desktop.base", + "Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.Redist.x64.OneCore.Desktop.base", + "Microsoft.VisualStudio.PackageGroup.VC.Tools.x86", + "Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Res", + "Microsoft.VisualCpp.Tools.HostX86.TargetX64", + "Microsoft.VC.14.34.17.4.Tools.HostX86.TargetX64.base", + "Microsoft.VC.14.34.17.4.Props.x64", + "Microsoft.VC.14.34.17.4.Tools.Hostx86.Targetx64.Res.base", + "Microsoft.VisualCpp.Tools.HostX86.TargetX86.Res", + "Microsoft.VisualCpp.Tools.HostX86.TargetX86", + "Microsoft.VC.14.34.17.4.Tools.HostX86.TargetX86.base", + "Microsoft.VC.14.34.17.4.Servicing.Compilers", + "Microsoft.VC.14.34.17.4.Props.x86", + "Microsoft.VC.14.34.17.4.Props", + "Microsoft.VC.14.34.17.4.Tools.HostX86.TargetX86.Res.base", + "Microsoft.VisualCpp.Tools.Core.Resources", + "Microsoft.VisualCpp.Tools.Core.x86", + "Microsoft.VC.14.34.17.4.Tools.Core.Props", + "Microsoft.VisualCpp.DIA.SDK", + "Microsoft.VisualCpp.Servicing.DIASDK", + "Microsoft.VisualCpp.CRT.x86.Desktop", + "Microsoft.VC.14.34.17.4.CRT.x86.Desktop.base", + "Microsoft.VisualCpp.CRT.x64.Desktop", + "Microsoft.VC.14.34.17.4.CRT.x64.Desktop.base", + "Microsoft.VisualCpp.CRT.Source", + "Microsoft.VC.14.34.17.4.CRT.Source.base", + "Microsoft.VisualCpp.CRT.Redist.X86", + "Microsoft.VC.14.34.17.4.CRT.Redist.X86.base", + "Microsoft.VisualCpp.CRT.Redist.X64", + "Microsoft.VisualCpp.CRT.Redist.Resources", + "Microsoft.VC.14.34.17.4.CRT.Redist.X64.base", + "Microsoft.VisualCpp.CRT.Headers", + "Microsoft.VC.14.34.17.4.CRT.Headers.base", + "Microsoft.VC.14.34.17.4.Servicing.CrtHeaders", + "Microsoft.VC.14.34.17.4.Servicing", + "Microsoft.VisualStudio.Component.VC.CoreIde", + "Microsoft.VisualStudio.VC.Ide.Pro", + "Microsoft.VisualStudio.VC.Ide.Pro.Resources", + "Microsoft.VisualStudio.VC.Templates.General", + "Microsoft.VisualStudio.VC.Templates.General.Resources", + "Microsoft.VisualStudio.VC.Items.Pro", + "Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced", + "Microsoft.VisualStudio.VC.Ide.x64", + "Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express", + "Microsoft.VisualStudio.VC.vcvars", + "Microsoft.VS.VC.vcvars.x86.Shortcuts", + "Microsoft.VS.VC.vcvars.x64.Shortcuts", + "Microsoft.VS.VC.vcvars.arm64_x64.Shortcuts", + "Microsoft.VisualStudio.VC.MSBuild.v170.X64.v143", + "Microsoft.VisualStudio.VC.MSBuild.v170.X64", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM.v143", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM", + "Microsoft.VisualStudio.VC.MSBuild.v170.x86.v143", + "Microsoft.VisualStudio.VC.MSBuild.v170.X86", + "Microsoft.VisualStudio.VC.MSBuild.v170.Base", + "Microsoft.VisualStudio.VC.MSBuild.v170.Base.Resources", + "Microsoft.VisualStudio.VC.Ide.WinXPlus", + "Microsoft.VisualStudio.VC.Ide.Dskx", + "Microsoft.VisualStudio.VC.Ide.Dskx.Resources", + "Microsoft.VisualStudio.VC.Ide.Base", + "Microsoft.VisualStudio.VC.Ide.LanguageService", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.Scripts", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.PythonDistro", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.10", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.9", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.8", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.7", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.6", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.5", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.4", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.3", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.2", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.1", + "Microsoft.VisualStudio.VC.Ide.VCPkgDatabase", + "Microsoft.VisualStudio.VC.Ide.Core", + "Microsoft.VisualStudio.VC.Ide.ProjectSystem", + "Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources", + "Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine", + "Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources", + "Microsoft.VisualStudio.VC.Ide.LanguageService.Resources", + "Microsoft.VisualStudio.VC.Llvm.Base", + "Microsoft.VisualStudio.VC.Ide.Base.Resources", + "Microsoft.Net.PackageGroup.4.8.1.Redist", + "Microsoft.VisualStudio.Component.IntelliCode", + "Microsoft.VisualStudio.IntelliCode.CSharp", + "Microsoft.VisualStudio.IntelliCode", + "Component.Microsoft.VisualStudio.LiveShare.2022", + "Microsoft.VisualStudio.Component.Debugger.JustInTime", + "Microsoft.VisualStudio.Debugger.ImmersiveActivateHelper.Msi", + "Microsoft.VisualStudio.Debugger.JustInTime", + "Microsoft.VisualStudio.Debugger.JustInTime.Msi", + "Microsoft.VisualStudio.LiveShare.2022", + "Microsoft.Icecap.Analysis", + "Microsoft.Icecap.Analysis.Resources", + "Microsoft.Icecap.Analysis.Resources.Targeted", + "Microsoft.Icecap.Collection.Msi", + "Microsoft.Icecap.Collection.Msi.Targeted", + "Microsoft.Icecap.Collection.Msi.Resources", + "Microsoft.Icecap.Collection.Msi.Resources.Targeted", + "Microsoft.DiagnosticsHub.Instrumentation", + "Microsoft.DiagnosticsHub.Instrumentation.Targeted", + "Microsoft.DiagnosticsHub.CpuSampling", + "Microsoft.DiagnosticsHub.CpuSampling.Targeted", + "Microsoft.PackageGroup.DiagnosticsHub.Platform", + "Microsoft.VisualStudio.InstrumentationEngine.ARM64", + "Microsoft.VisualStudio.InstrumentationEngine", + "Microsoft.DiagnosticsHub.Runtime.ExternalDependencies", + "SQLiteCore", + "SQLiteCore.Targeted", + "Microsoft.DiagnosticsHub.Runtime.ExternalDependencies.Targeted", + "Microsoft.DiagnosticsHub.Runtime", + "Microsoft.DiagnosticsHub.Runtime.Targeted", + "Microsoft.DiagnosticsHub.Collection.ExternalDependencies.arm64", + "Microsoft.DiagnosticsHub.Collection", + "Microsoft.DiagnosticsHub.Collection.Service", + "Microsoft.VisualStudio.VC.Ide.MDD", + "Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager", + "Microsoft.VisualStudio.VisualC.Utilities", + "Microsoft.VisualStudio.VisualC.Utilities.Resources", + "Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager.Resources", + "Microsoft.VisualStudio.VC.Ide.ResourceEditor", + "Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources", + "Microsoft.VisualStudio.PackageGroup.TestTools.Core", + "Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V2.CLI", + "Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI", + "Microsoft.VisualStudio.TestTools.Pex.Common", + "Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V1.CLI", + "Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.Legacy", + "Microsoft.VisualStudio.PackageGroup.MinShell.Interop", + "Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Msi", + "Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Common", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips.Resources", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.TestSettings", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Professional", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Common", + "Microsoft.VisualStudio.TestTools.TP.Legacy.Common.Res", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core.Resources", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Agent", + "Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.IDE", + "Microsoft.VisualStudio.Cache.Service", + "Microsoft.VisualStudio.TestTools.TestWIExtension", + "Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI", + "Microsoft.VisualStudio.TestTools.TestPlatform.IDE", + "Microsoft.VisualStudio.PackageGroup.TestTools.CodeCoverage", + "Microsoft.VisualStudio.PackageGroup.TestTools.DataCollectors", + "Microsoft.VisualStudio.Component.NuGet", + "Microsoft.CredentialProvider", + "Microsoft.VisualStudio.NuGet.Licenses", + "Microsoft.VisualStudio.Component.TextTemplating", + "Microsoft.VisualStudio.TextTemplating.MSBuild", + "Microsoft.VisualStudio.TextTemplating.Integration", + "Microsoft.VisualStudio.TextTemplating.Core", + "Microsoft.VisualStudio.TextTemplating.Integration.Resources", + "Microsoft.VisualCpp.CRT.ClickOnce.Msi", + "Microsoft.VisualStudio.Component.Roslyn.LanguageServices", + "Microsoft.VisualStudio.InteractiveWindow", + "Microsoft.DiaSymReader.Native", + "Microsoft.VisualCpp.Redist.14", + "Microsoft.VisualCpp.Redist.14", + "Microsoft.VisualCpp.Servicing.Redist", + "Microsoft.VisualStudio.PackageGroup.StaticAnalysis", + "Microsoft.VisualStudio.StaticAnalysis.IDE", + "Microsoft.VisualStudio.StaticAnalysis.IDE.Resources", + "Microsoft.VisualStudio.StaticAnalysis.FxCop.Resources", + "Microsoft.VisualStudio.StaticAnalysis.auxil", + "Microsoft.VisualStudio.StaticAnalysis.auxil.Resources", + "Roslyn.VisualStudio.Setup.ServiceHub", + "Microsoft.Component.MSBuild", + "Microsoft.NuGet.Build.Tasks.Setup", + "Microsoft.VisualStudio.Component.Roslyn.Compiler", + "Microsoft.CodeAnalysis.Compilers", + "Microsoft.VisualStudio.Component.JavaScript.TypeScript", + "Microsoft.VisualStudio.JavaScript.ProjectSystem", + "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions", + "Microsoft.VisualStudio.ProTools", + "sqlsysclrtypes", + "SQLCommon", + "Microsoft.VisualStudio.ProTools.Resources", + "Microsoft.VisualStudio.Web.Scaffolding", + "Microsoft.VisualStudio.WebToolsExtensions", + "Microsoft.VisualStudio.ConnectedServices.Core", + "Microsoft.VisualStudio.WebTools", + "Microsoft.VisualStudio.WebToolsExtensions.MSBuild", + "Microsoft.VisualStudio.WebTools.Resources", + "Microsoft.VisualStudio.WebTools.WSP.FSA", + "Microsoft.VisualStudio.WebTools.WSP.FSA.Resources", + "Microsoft.VisualStudio.PackageGroup.Debugger.Script", + "Microsoft.VisualStudio.Component.TypeScript.TSServer", + "Microsoft.VisualStudio.Package.TypeScript.TSServer", + "Microsoft.VisualStudio.PackageGroup.JavaScript.Language", + "Microsoft.VisualStudio.Package.NodeJs", + "TypeScript.Build", + "TypeScript.LanguageService", + "TypeScript.Tools", + "Microsoft.VisualStudio.PackageGroup.Community", + "Microsoft.VisualStudio.Community.VB.x86", + "Microsoft.VisualStudio.Community.VB.x64", + "Microsoft.VisualStudio.PackageGroup.Core", + "Microsoft.VisualStudio.CodeSense.Community", + "Microsoft.VisualStudio.TestTools.TeamFoundationClient", + "Microsoft.VisualStudio.PackageGroup.Debugger.Core", + "Microsoft.VisualStudio.Debugger.BrokeredServices", + "Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost", + "Microsoft.VisualStudio.Debugger.AzureAttach", + "Microsoft.VisualStudio.Web.Azure.Common", + "Microsoft.WebTools.Shared", + "Microsoft.WebTools.DotNet.Core.ItemTemplates", + "Microsoft.VisualStudio.PackageGroup.Debugger.TimeTravel.Replay", + "Microsoft.VisualStudio.VC.Ide.Debugger", + "Microsoft.VisualStudio.VC.Ide.Debugger.Concord", + "Microsoft.VisualStudio.VC.Ide.Debugger.Concord.Resources", + "Microsoft.VisualStudio.VC.Ide.Debugger.Resources", + "Microsoft.VisualStudio.VC.Ide.Common", + "Microsoft.VisualStudio.VC.Ide.Common.Resources", + "Microsoft.VisualStudio.Debugger.CollectionAgents", + "Microsoft.VisualStudio.Debugger.Parallel", + "Microsoft.VisualStudio.Debugger.Parallel.Resources", + "Microsoft.VisualStudio.Debugger.Managed", + "Microsoft.CodeAnalysis.ExpressionEvaluator", + "Microsoft.CodeAnalysis.VisualStudio.Setup", + "Microsoft.VisualStudio.Debugger.Concord.Managed", + "Microsoft.VisualStudio.Debugger.Concord.Managed.Resources", + "Microsoft.VisualStudio.Debugger.Managed.Resources", + "Microsoft.VisualStudio.Debugger.TargetComposition", + "Microsoft.VisualStudio.Debugger.TargetComposition.Remote.arm64", + "Microsoft.VisualStudio.Debugger.TargetComposition.Remote", + "Microsoft.VisualStudio.Debugger.TargetComposition.Remote", + "Microsoft.VisualStudio.Debugger.Remote", + "Microsoft.VisualStudio.Debugger.Concord.Remote", + "Microsoft.VisualStudio.Debugger.Concord.Remote.Resources", + "Microsoft.VisualStudio.Debugger.Remote", + "Microsoft.VisualStudio.Debugger.Remote.ARM64", + "Microsoft.VisualStudio.Debugger.Concord.Remote.ARM64", + "Microsoft.VisualStudio.Debugger.Concord.Remote.Resources.ARM64", + "Microsoft.VisualStudio.Debugger.Remote.ARM", + "Microsoft.VisualStudio.Debugger.Concord.Remote.ARM", + "Microsoft.VisualStudio.Debugger.Concord.Remote.Resources.ARM", + "Microsoft.VisualStudio.Debugger.Remote.Resources.ARM", + "Microsoft.VisualStudio.Debugger.Remote.Resources.ARM64", + "Microsoft.VisualStudio.Debugger.Concord.Remote", + "Microsoft.VisualStudio.Debugger.Concord.Remote.Resources", + "Microsoft.VisualStudio.Debugger.Remote.Resources", + "Microsoft.VisualStudio.Debugger.Remote.Resources", + "Microsoft.VisualStudio.Debugger", + "Microsoft.VisualStudio.VC.MSVCDis", + "Microsoft.IntelliTrace.DiagnosticsHub", + "Microsoft.VisualStudio.Debugger.Concord", + "Microsoft.VisualStudio.Debugger.Concord.Resources", + "Microsoft.VisualStudio.Debugger.Resources", + "Microsoft.VisualStudio.Debugger.Package.DiagHub.Client", + "Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client", + "Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client", + "Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client", + "Microsoft.PackageGroup.ClientDiagnostics", + "Microsoft.VisualStudio.AppResponsiveness", + "Microsoft.VisualStudio.AppResponsiveness.Targeted", + "Microsoft.VisualStudio.AppResponsiveness.Resources", + "Microsoft.VisualStudio.ClientDiagnostics", + "Microsoft.VisualStudio.ClientDiagnostics.Targeted", + "Microsoft.VisualStudio.ClientDiagnostics.Resources", + "Microsoft.VisualStudio.PackageGroup.CommunityCore", + "Microsoft.VisualStudio.ProjectSystem.Full", + "Microsoft.VisualStudio.LiveShareApi", + "Microsoft.VisualStudio.ProjectSystem.Query", + "Microsoft.VisualStudio.ProjectSystem", + "Microsoft.VisualStudio.Community.x86", + "Microsoft.VisualStudio.Community.x64", + "Microsoft.VisualStudio.Community.Msi.Resources", + "Microsoft.VisualStudio.Community.Msi", + "Microsoft.VisualStudio.Community.Shared.Msi", + "Microsoft.VisualStudio.Devenv.Msi", + "Microsoft.VisualStudio.Devenv.Shared.Msi", + "Microsoft.VisualStudio.MinShell.Interop.Msi", + "Microsoft.VisualStudio.MinShell.Interop.Shared.Msi", + "Microsoft.VisualStudio.Editors", + "Microsoft.VisualStudio.Workload.CoreEditor", + "Microsoft.VisualStudio.Component.CoreEditor", + "Microsoft.VisualStudio.PackageGroup.CoreEditor", + "Microsoft.WebView2", + "Microsoft.VisualStudio.ScriptedHost", + "Microsoft.VisualStudio.ScriptedHost.Targeted", + "Microsoft.VisualCpp.Tools.Common.UtilsPrereq", + "Microsoft.VisualCpp.Tools.Common.Utils", + "Microsoft.VisualCpp.Tools.Common.Utils.Resources", + "Microsoft.VisualStudio.PackageGroup.VsDevCmd", + "Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk", + "Microsoft.VisualStudio.VsDevCmd.Core.WinSdk", + "Microsoft.VisualStudio.VsDevCmd.Core.DotNet", + "Microsoft.VisualStudio.VC.DevCmd", + "Microsoft.VisualStudio.VC.DevCmd.Resources", + "Microsoft.VisualStudio.VirtualTree", + "Microsoft.DiaSymReader", + "Microsoft.Build.Dependencies", + "Microsoft.Build.FileTracker.Msi", + "Microsoft.Build", + "Microsoft.VisualStudio.PackageGroup.NuGet", + "Microsoft.DataAI.NuGetRecommender", + "Microsoft.VisualStudio.NuGet.Core", + "Microsoft.Build.Arm64", + "Microsoft.Build.UnGAC", + "Microsoft.VisualStudio.TextMateGrammars", + "Microsoft.VisualStudio.Platform.Markdown", + "Microsoft.VisualStudio.Platform.CrossRepositorySearch", + "Microsoft.VisualStudio.PackageGroup.TeamExplorer.Common", + "Microsoft.VisualStudio.TeamExplorer", + "Microsoft.VisualStudio.PackageGroup.ServiceHub", + "Microsoft.ServiceHub.Node", + "Microsoft.ServiceHub.Managed", + "Microsoft.ServiceHub.arm64", + "Microsoft.VisualStudio.ProjectServices", + "Microsoft.VisualStudio.OpenFolder.VSIX", + "Microsoft.VisualStudio.FileHandler.Msi", + "Microsoft.VisualStudio.FileHandler.Msi", + "Microsoft.VisualStudio.PackageGroup.MinShell", + "Microsoft.VisualStudio.MinShell.Msi", + "Microsoft.VisualStudio.MinShell.Shared.Msi", + "Microsoft.VisualStudio.MinShell.Msi.Resources", + "Microsoft.VisualStudio.MinShell.Interop", + "CoreEditorFonts", + "Microsoft.VisualStudio.Log", + "Microsoft.VisualStudio.Log.Targeted", + "Microsoft.VisualStudio.Log.Resources", + "Microsoft.VisualStudio.Finalizer", + "Microsoft.VisualStudio.Devenv", + "Microsoft.VisualStudio.Devenv.Resources", + "Microsoft.VisualStudio.CoreEditor", + "Microsoft.VisualStudio.Navigation.RichCodeNav", + "Microsoft.VisualStudio.Platform.NavigateTo", + "Microsoft.VisualStudio.Connected", + "SQLitePCLRaw", + "SQLitePCLRaw.Targeted", + "Microsoft.VisualStudio.Connected.Auto", + "Microsoft.VisualStudio.Connected.Auto.Resources", + "Microsoft.VisualStudio.AzureSDK", + "Microsoft.VisualStudio.PerfLib", + "Microsoft.VisualStudio.Connected.Resources", + "Microsoft.Net.PackageGroup.4.8.Redist", + "Microsoft.VisualStudio.PackageGroup.Progression", + "Microsoft.VisualStudio.PerformanceProvider", + "Microsoft.VisualStudio.GraphModel", + "Microsoft.VisualStudio.GraphProvider", + "Microsoft.VisualStudio.Community.VB.Targeted", + "Microsoft.VisualStudio.Community.VB.Neutral", + "Microsoft.VisualStudio.Community.CSharp.Targeted", + "Microsoft.VisualStudio.Community.CSharp.Neutral", + "Microsoft.VisualStudio.Community.ProductArch.TargetedExtra", + "Microsoft.VisualStudio.Community.ProductArch.Targeted", + "Microsoft.VisualStudio.Community.ProductArch.NeutralExtra", + "Microsoft.DiaSymReader.PortablePdb", + "Microsoft.IntelliTrace.CollectorCab", + "Microsoft.VisualStudio.Community.VB.Resources.Targeted", + "Microsoft.VisualStudio.Community.VB.Resources.Neutral", + "Microsoft.VisualStudio.Community.CSharp.Resources.Targeted", + "Microsoft.VisualStudio.Community.CSharp.Resources.Neutral", + "Microsoft.VisualStudio.Community.ProductArch.Resources.Targeted", + "Microsoft.VisualStudio.Community.ProductArch.Resources.NeutralExtra", + "Microsoft.VisualStudio.Net.Eula.Resources", + "Microsoft.VisualStudio.Community.ProductArch.Resources.Neutral", + "Microsoft.VisualStudio.WebSiteProject.DTE", + "Microsoft.VisualStudio.Diagnostics.AspNetHelper", + "Microsoft.VisualStudio.Diagnostics.AspNetHelper.Standard", + "Microsoft.MSHtml", + "Microsoft.VisualStudio.Platform.CallHierarchy", + "Microsoft.VisualStudio.Community.ProductArch.Neutral", + "Microsoft.VisualStudio.MinShell", + "Microsoft.VisualStudio.VsWebProtocolSelector.Msi", + "Microsoft.Net.6.WindowsDesktop.Runtime", + "Microsoft.Net.6.Runtime", + "Microsoft.VisualStudio.PackageGroup.Setup.Common", + "Microsoft.VisualStudio.Setup.WMIProvider", + "Microsoft.VisualStudio.Setup.Configuration.Interop", + "Microsoft.VisualStudio.Setup.Configuration", + "Microsoft.VisualStudio.Extensibility.Container", + "Microsoft.VisualStudio.LanguageServer", + "Microsoft.VisualStudio.Platform.Terminal", + "Microsoft.VisualStudio.MefHosting", + "Microsoft.VisualStudio.Initializer", + "Microsoft.VisualStudio.ExtensionManager", + "Microsoft.VisualStudio.Platform.Editor", + "Microsoft.VisualStudio.MinShell.Targeted", + "Microsoft.VisualStudio.NativeImageSupport", + "Microsoft.VisualStudio.Devenv.Config", + "Microsoft.VisualStudio.MinShell.Resources.arm64", + "Microsoft.VisualStudio.MinShell.Auto", + "Microsoft.VisualStudio.MinShell.Auto.Resources", + "Microsoft.VisualStudio.Branding.Community" + ] + } +] diff --git a/test/fixtures/ca-bundle.crt b/test/fixtures/ca-bundle.crt deleted file mode 100644 index fb1dea98a7..0000000000 --- a/test/fixtures/ca-bundle.crt +++ /dev/null @@ -1,40 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDJjCCAg4CAhnOMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD -VQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZMBcGA1UECgwQU3Ryb25n -TG9vcCwgSW5jLjESMBAGA1UECwwJU3Ryb25nT3BzMRowGAYDVQQDDBFjYS5zdHJv -bmdsb29wLmNvbTAeFw0xNTEyMDgyMzM1MzNaFw00MzA0MjQyMzM1MzNaMBkxFzAV -BgNVBAMMDnN0cm9uZ2xvb3AuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAwOYI7OZ2FX/YjRgLZoDQlbPc5UZXU/j0e1wwiJNPtPEax9Y5Uoza0Pnt -Ikzkc2SfvQ+IJrhXo385tI0W5juuqbHnE7UrjUuPjUX6NHevkxcs/flmjan5wnZM -cPsGhH71WDuUEEflvZihf2Se2x+xgZtMhc5XGmVmRuZFYKvkgUhA2/w8/QrK+jPT -n9QRJxZjWNh2RBdC1B7u4jffSmOSUljYFH1I2eTeY+Rdi6YUIYSU9gEoZxsv3Tia -SomfMF5jt2Mouo6MzA+IhLvvFjcrcph1Qxgi9RkfdCMMd+Ipm9YWELkyG1bDRpQy -0iyHD4gvVsAqz1Y2KdRSdc3Kt+nTqwIDAQABoxkwFzAVBgNVHREEDjAMhwQAAAAA -hwR/AAABMA0GCSqGSIb3DQEBBQUAA4IBAQAhy4J0hML3NgmDRHdL5/iTucBe22Mf -jJjg2aifD1S187dHm+Il4qZNO2plWwAhN0h704f+8wpsaALxUvBIu6nvlvcMP5PH -jGN5JLe2Km3UaPvYOQU2SgacLilu+uBcIo2JSHLV6O7ziqUj5Gior6YxDLCtEZie -Ea8aX5/YjuACtEMJ1JjRqjgkM66XAoUe0E8onOK3FgTIO3tGoTJwRp0zS50pFuP0 -PsZtT04ck6mmXEXXknNoAyBCvPypfms9OHqcUIW9fiQnrGbS/Ri4QSQYj0DtFk/1 -na4fY1gf3zTHxH8259b/TOOaPfTnCEsOQtjUrWNR4xhmVZ+HJy4yytUW ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDbzCCAlcCAmm6MA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAlVTMQswCQYD -VQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZMBcGA1UECgwQU3Ryb25n -TG9vcCwgSW5jLjESMBAGA1UECwwJU3Ryb25nT3BzMRowGAYDVQQDDBFjYS5zdHJv -bmdsb29wLmNvbTAeFw0xNTEyMDgyMzM1MzNaFw00MzA0MjQyMzM1MzNaMH0xCzAJ -BgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZ -MBcGA1UECgwQU3Ryb25nTG9vcCwgSW5jLjESMBAGA1UECwwJU3Ryb25nT3BzMRow -GAYDVQQDDBFjYS5zdHJvbmdsb29wLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBANfj86jkvvYDjHBgiqWhk9Cj+bqiMq3MqnV0CBO4iuK33Fo6XssE -H+yVdXlIBFbFe6t655MdBVOR2Sfj7WqNh96vhu6PyDHiwcQlTaiLU6nhIed1J4Wv -lvnJHFmp8Wbtx5AgLT4UYu03ftvXEl2DLi3vhSL2tRM1ebXHB/KPbRWkb25DPX0P -foOHot3f2dgNe2x6kponf7E/QDmAu3s7Nlkfh+ryDhgGU7wocXEhXbprNqRqOGNo -xbXgUI+/9XDxYT/7Gn5LF/fPjtN+aB0SKMnTsDhprVlZie83mlqJ46fOOrR+vrsQ -mi/1m/TadrARtZoIExC/cQRdVM05EK4tUa8CAwEAATANBgkqhkiG9w0BAQsFAAOC -AQEAQ7k5WhyhDTIGYCNzRnrMHWSzGqa1y4tJMW06wafJNRqTm1cthq1ibc6Hfq5a -K10K0qMcgauRTfQ1MWrVCTW/KnJ1vkhiTOH+RvxapGn84gSaRmV6KZen0+gMsgae -KEGe/3Hn+PmDVV+PTamHgPACfpTww38WHIe/7Ce9gHfG7MZ8cKHNZhDy0IAYPln+ -YRwMLd7JNQffHAbWb2CE1mcea4H/12U8JZW5tHCF6y9V+7IuDzqwIrLKcW3lG17n -VUG6ODF/Ryqn3V5X+TL91YyXi6c34y34IpC7MQDV/67U7+5Bp5CfeDPWW2wVSrW+ -uGZtfEvhbNm6m2i4UNmpCXxUZQ== ------END CERTIFICATE----- diff --git a/test/fixtures/ca.crt b/test/fixtures/ca.crt deleted file mode 100644 index aaf97575b1..0000000000 --- a/test/fixtures/ca.crt +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDZDCCAkwCCQCAzfCLqrJvuTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV -UzELMAkGA1UECAwCQ0ExEDAOBgNVBAoMB05vZGUuanMxETAPBgNVBAsMCG5vZGUt -Z3lwMRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEGJ1aWxkQG5v -ZGVqcy5vcmcwHhcNMTkwNjIyMDYyMjMzWhcNMjIwNDExMDYyMjMzWjB0MQswCQYD -VQQGEwJVUzELMAkGA1UECAwCQ0ExEDAOBgNVBAoMB05vZGUuanMxETAPBgNVBAsM -CG5vZGUtZ3lwMRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEGJ1 -aWxkQG5vZGVqcy5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS -CHjvtVW4HdbbUwZ/ZV9s6U4x0KSoyNQrsCZjB8kRpFPe50DS5mfmu2SNBGYKRgzk -4QEEwFB9N2o8YTWsCefSRl6ti4ToPZqulU4hhRKYrEGtMJcRzi3IN7s200JaO3UH -01Su8ruO0NESb5zEU1Ykfh8Lub8TGEAINmgI61d/5d5Aq3kDjUHQJt1Ekw03Ylnu -juQyCGZxLxnngu0mIvwzyL/UeeUgsfQLzvppUk6In7tC1zzMjSPWo0c8qu6KvrW4 -bKYnkZkzdQifzbpO5ERMEsh5HWq0uHa6+dgcVHFvlhdqF4Uat87ygNplVf0txsZB -MNVqbz1k6xkZYMnzDoydAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADspZGtKpWxy -J1W3FA1aeQhMvequQTcMRz4avkm4K4HfTdV1iVD4CbvdezBphouBlyLVLDFJP7RZ -m7dBJVgBwnxufoFLne8cR2MGqDRoySbFT1AtDJdxabE6Fg+QGUpgOQfeBJ6ANlSB -+qJ+HG4QA+Ouh5hxz9mgYwkIsMUABHiwENdZ/kT8Edw4xKgd3uH0YP4iiePMD66c -rzW3uXH5J1jnKgBlpxtog4P6dHCcoq+PZJ17W5bdXNyqC1LPzQqniZ2BNcEZ4ix3 -slAZAOWD1zLLGJhBPMV1fa0sHNBWc6oicr3YK/IDb0cp9kiLvnUu1pHy+LWQGqtC -rceJuGsnJEQ= ------END CERTIFICATE----- diff --git a/test/fixtures/certs.js b/test/fixtures/certs.js new file mode 100644 index 0000000000..f03f1de0d7 --- /dev/null +++ b/test/fixtures/certs.js @@ -0,0 +1,151 @@ +module.exports['ca.key'] = ` +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAtTbG0k2UFUyCdZuip0TTEtXRHh57qosegrpHPBreSNTxt7OT +KfOUZp2rToTHeN9w0ZbV2eKRI5AuFx8Cmlm73/KIHKzSNTBATGMeeHnGaxvL/W/s +KJdTDRNf7/qCXHQ+gsuEWWCFzOZuHmmAQa2IBX2HAQTqXJI8+2iJ9gytFfJLxjqy +6O4u9ugZVHSyQJWs49tGRcWMlNm7EMStADFvJn3S11xe/kwIA2mSI/eddDnzL0Mx +AkR9dQBL66xOABLL5v3QQdhipfHluX6HLbDd/1YsFTuOpgvLRlr72rTAFrQZCokV +hXPiqstn5zJFW5arHakvMR0+OPaICF5feh/4qQIDAQABAoIBAHWg6exnWUF+GY0Y +CrwDS/QFASpI5UNt7M809bqJQlMKjyEMmvF3YJQ/soxUWlsWx1f1TjmR/V6VX6W4 +hmsE5pRXDY13jTfja0lqacQQYAD02TRY63XpzIpHUlYnSWmUN2OVkgKmShQYW9C3 +8P4xE4Nk2TaLJ0oRzy3uzOb/kXcVaJfknBRUnOhuaTSs+w4l4pPXueYA7xuHgVsL +Qq0S4kK+PmdwCMB7gzlAAQhCM3vQ1U4cjC9JIIKSmPy7BcvD0kBfVPIFQ2byGpA1 +VkWBLSyeig0YxA5oIshK5cLiDIfBIiCSEzm4AMhVhGf0tbGEwiPljxKjbarYUUIi +ATMk83UCgYEA7kKeOveuPbMqxmT42swfa9OU5jLUjH+VExU0Kv3BbEjv/OGt0fac +/cs1Ze3vnrtCHudVajocFjydb8B4c62DbA4/T+LcUw/HaMaORbOoICQidi/zZ1Lj +gjg8Ip2WKXEhSAwqUpaFd6w16NZOxiTh+NDaRKywwbe8j57eDH4uR6MCgYEAwrTS +q5ra6+WDGUFMs0y3GMbL8j14PGhxBQBYSTM//NysI+EM6eeKn1cV3BbphEw//jgE +0pVokkjvLAQWWEG2dZyRxRE3YAMgOAIPx5zbJCim3iBVuoqY9ckLg2jF8Fqqubsb +3Rf2/Xzn/rFqsXdhsjGcJpdN66T9aEjwEkAnc0MCgYA5cOYk4UGormFJo147oaqR +nFjxhp+nn7qY9yu0kajoKk1xchct337J0Qv2nv5+DjdKrArzqT7MPaDXKFfhy5s7 +mdO5tr/XZp50rCnws/d8iDmmtLjB2EHxSw10avmg1B1p+UTa1F8pEuOMVt529r1j +9zYoCFo02c8j8PEnoeQWcQKBgQCVBCuQZu5SSM/zTkTTnU0sy0lf1qflI9IMD92B ++JVqg8HDnAR0KF+x38a9MVP7ixgXCuy19t+XxfY269HmLjTlArWV671D4GCSPRGy +plwZ6nr72ieCo3y57+q94jxL3jh3+bozlpnUG/q6tTKBLGs7JDjsWDSsuxOu8tO6 +RBttXQKBgB6LQFOTjDMfsFHKsnQXFUZId3GG/iLg3WCWxEo88T5Rq3JIR0zDpW8H +cKhl/sPY+JVHsxizNCMPtp7Hn7GrB6D/v9LbO0jpG2U0BFiJ6zhiDopbP9B0EAW4 +5JJ+JGKRKoCxs3DmSVyns0gU4j4rVte97UWyVy5TZ8Acr/qrgOA1 +-----END RSA PRIVATE KEY----- +` + +module.exports['ca.crt'] = ` +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIUDA0GrvcnG41XT6LYFeNwvq8YV1UwDQYJKoZIhvcNAQEL +BQAwXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRAwDgYDVQQKDAdOb2RlLmpz +MREwDwYDVQQLDAhub2RlLWd5cDEcMBoGA1UEAwwTbm9kZS1neXAubm9kZWpzLm9y +ZzAeFw0yMjA1MTEwNDIyMjRaFw00OTA5MjUwNDIyMjRaMF0xCzAJBgNVBAYTAlVT +MQswCQYDVQQIDAJDQTEQMA4GA1UECgwHTm9kZS5qczERMA8GA1UECwwIbm9kZS1n +eXAxHDAaBgNVBAMME25vZGUtZ3lwLm5vZGVqcy5vcmcwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC1NsbSTZQVTIJ1m6KnRNMS1dEeHnuqix6Cukc8Gt5I +1PG3s5Mp85RmnatOhMd433DRltXZ4pEjkC4XHwKaWbvf8ogcrNI1MEBMYx54ecZr +G8v9b+wol1MNE1/v+oJcdD6Cy4RZYIXM5m4eaYBBrYgFfYcBBOpckjz7aIn2DK0V +8kvGOrLo7i726BlUdLJAlazj20ZFxYyU2bsQxK0AMW8mfdLXXF7+TAgDaZIj9510 +OfMvQzECRH11AEvrrE4AEsvm/dBB2GKl8eW5foctsN3/ViwVO46mC8tGWvvatMAW +tBkKiRWFc+Kqy2fnMkVblqsdqS8xHT449ogIXl96H/ipAgMBAAGjUzBRMB0GA1Ud +DgQWBBT6LcYYABEOAMv4hI/5bC82rGlD/DAfBgNVHSMEGDAWgBT6LcYYABEOAMv4 +hI/5bC82rGlD/DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA9 +D+qoKw0njub+NaFRS2DFbSiKb5JKTxVjU5aNusFONFLSXBuRpnYyjjkXpJy8JMWz +g8GFDEPP6kiSb8xaPNrFcUzb4PFzJabNTuaLJpBpd2gNBj5AeYwwpRa2DPv/b4yw +y2mfULuCWS09ZAguI2OcaARlAsFxYN0IuQ6pN1AvGFGee67ve9l2VF/hhwEi4lCk +MM0CWlP6COJ8TX7X0MTtexVOgo9m3hBuTSYEZClYFIdSOk10xkPl8Y3Iz/x6mzfK +Uu2l2ZtYvSdAX1CQMds3ZWt0ChNNEjOKPv4g2QSDhGkiqrmi4wUS81g68wKqOpqn +GbN8uKxIfyMjqZKaujPR +-----END CERTIFICATE----- +` + +module.exports['server.key'] = ` +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDpxqKqzq8PuOuo +M09X1gdh6V1nMmJ6Oqk/d8ZSAHhGBTjB5BBILtrxJPAdsNCRc8gPCtSuAzu9r0ct +D2znJjto8HO3a0s/4mlqMQ8iSvfH0c8nGLPxRXg0C9tR0VOyqJrqAPn9X6utxVQj +H2jLjZngZllhqlxIUxYuXO7MZfC2MQ4DRsp6GaJTftcOxTxevMdT6lK0yl3mDn0W +DyV9aWR5oCVXKIRK7jmF9bi9ETHwJHffFrduaaKYLQ/UOEtNek/pJsz0DNO0ePkm +DAt0GQkX3hmKd0VRgGEtaO+MAGbrDucPuDylMkC1GJm1lq6+6rkyQRNoAd8/yOJD +GihBJmLPAgMBAAECggEBAL3+WM/3IGHnyWavJMnfQaq6rdWkJlLugAT8BCs7BITr +04AJKY5wvjID8j4/KJM+BRbsl4NBT3lPDcq6YajO8rPL0E/+nG60RTYv3vvg79Xv +V6uPsRbifdnW1Q1+0cY+r4CFAKeC7JVS7ZmJ+nKMh8XPiM8OVOfW1w0hLFbkdqiq +UetA5H0oiJr0rFWh9Gfzc0avpmawXmZJqK8lKWB1rt2teu3bQWqn20dGr2IyCipz +KlGh3QImYogjqWEqPyowPGxnq8KWQ40Pjx61dy6cqYrw77yxLHGR8Az+TlRQZf/K +BeT3UkXCU5BTyC3PKZJpcYB/GMB8GBKRdNK+8H3OXskCgYEA963tUnLoiCwJjxvv +gIiMY5mIUAMnTDsCxSYekfkDvt4qdttn/+Y8/5/lXMSlCt+WZcXH0V8gmVOMqfHB +QRXWpi0uJnl9sUllb80Mw5PnS317UlJIbkro3crVUhIbrn9tKVFP1GO9xszNda8E +MkHV8FGmSaihXGnA8KEkTKg1CisCgYEA8aEjATIpDXyxQM4M9B1S0jI/nHOrg2lr +dMKQWJVruuvwrrZl6CFNIm2/PBXyHjCXqROXs7aXkE3vfRSypYNKBZl7BX08c0nE +koMVXwhGbSbUXjFx5bcUKaG/2eOK+ZV4ivNQokq1iIK+WKINAfP69ewzD7EAgbBg +KY7owSxka+0CgYB4Urh+W3B35tzl9y5NBQkewdGk/UM0F17rI++p/o1BRnDeuQw3 +F0T+8lDc1nNPavuHiaPfJRWTJzGoxdeapN9Yb46CBnd3jy6GN9lBkjLFS7qDbZHe +cunaBdXIPx/Pj/waHHRpu+LQF2KhD1s8hxtF2oSsOA3b9UxUGhSmYPkTbQKBgEP8 +muTTQEnTM+yQDYUCWzNZgBx9T10CZIHN3N+P62gEywvdtn7CH/n39z7ozd9AvOuN +37lpPuwTgbcoA7weXM2Gid7ZhhDKSM0QpQrAQVClBEwcjXedM8cjA+BC7e+b5vbx +z1ZavwlSAEzgC9jo1Uws0ZEwtHvJLMWEuGjiHL9hAoGAWEbj2cxhpCKTK3C8Qf+C +BscBwAZKmUasdWQBUzRFpR1UAO3fFBatjMPwrFYnt+ZgiCXTGFcoEa7mjoP/r5Mh +j1nRCoPQVcbmB1B9AtiaEa1AA+BqYF1r2aErbcsGrCV5OHU7TYFk1dep1SAQP/0W +9MQ+1Af5ttYSFYlJLnWJo4M= +-----END PRIVATE KEY----- +` + +module.exports['server.crt'] = ` +-----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIJALrth9K8D7HIMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV +BAYTAlVTMQswCQYDVQQIDAJDQTEQMA4GA1UECgwHTm9kZS5qczERMA8GA1UECwwI +bm9kZS1neXAxHDAaBgNVBAMME25vZGUtZ3lwLm5vZGVqcy5vcmcwHhcNMjMwOTI4 +MDUxODM2WhcNMzMwOTI1MDUxODM2WjBgMQswCQYDVQQGEwJVUzETMBEGA1UECAwK +Q2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEQMA4GA1UECgwHTm9k +ZS5qczESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA6caiqs6vD7jrqDNPV9YHYeldZzJiejqpP3fGUgB4RgU4weQQSC7a +8STwHbDQkXPIDwrUrgM7va9HLQ9s5yY7aPBzt2tLP+JpajEPIkr3x9HPJxiz8UV4 +NAvbUdFTsqia6gD5/V+rrcVUIx9oy42Z4GZZYapcSFMWLlzuzGXwtjEOA0bKehmi +U37XDsU8XrzHU+pStMpd5g59Fg8lfWlkeaAlVyiESu45hfW4vREx8CR33xa3bmmi +mC0P1DhLTXpP6SbM9AzTtHj5JgwLdBkJF94ZindFUYBhLWjvjABm6w7nD7g8pTJA +tRiZtZauvuq5MkETaAHfP8jiQxooQSZizwIDAQABMA0GCSqGSIb3DQEBCwUAA4IB +AQBwgEyrqJOV8SC7PVTtEOqfSyrM7lJjVcmwXEIFPVCPxXnDtLS9+OaQe9ybjOR/ +Bi/AvZK4gwsV9G5Bvbl0/sphYEKYLEpP76jhdETcBwhaEgK3itumoREeriut4bZI +OM6b1O45CoD67Lm87CUwLOdcNzPu4k7mat+xog5aFwaQuRjLBmmZcjl41QjVr9ti +La4PCMh7NwVMtHRqbYvgq785PsKAh+j4FSX1sj9NRzRPoJJ2qsre1Qn5tL/i6ovj +6s+3GxOQ5I1UzJX22PZFu003a582ha1CEFM0VaeDzzwbGNcV5SP+g2nw55zx9YRR +Rg8nGmjRuRtbs+/XAre2eQ5p +-----END CERTIFICATE----- +` + +module.exports['ca-bundle.crt'] = ` +-----BEGIN CERTIFICATE----- +MIIDJjCCAg4CAhnOMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD +VQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZMBcGA1UECgwQU3Ryb25n +TG9vcCwgSW5jLjESMBAGA1UECwwJU3Ryb25nT3BzMRowGAYDVQQDDBFjYS5zdHJv +bmdsb29wLmNvbTAeFw0xNTEyMDgyMzM1MzNaFw00MzA0MjQyMzM1MzNaMBkxFzAV +BgNVBAMMDnN0cm9uZ2xvb3AuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAwOYI7OZ2FX/YjRgLZoDQlbPc5UZXU/j0e1wwiJNPtPEax9Y5Uoza0Pnt +Ikzkc2SfvQ+IJrhXo385tI0W5juuqbHnE7UrjUuPjUX6NHevkxcs/flmjan5wnZM +cPsGhH71WDuUEEflvZihf2Se2x+xgZtMhc5XGmVmRuZFYKvkgUhA2/w8/QrK+jPT +n9QRJxZjWNh2RBdC1B7u4jffSmOSUljYFH1I2eTeY+Rdi6YUIYSU9gEoZxsv3Tia +SomfMF5jt2Mouo6MzA+IhLvvFjcrcph1Qxgi9RkfdCMMd+Ipm9YWELkyG1bDRpQy +0iyHD4gvVsAqz1Y2KdRSdc3Kt+nTqwIDAQABoxkwFzAVBgNVHREEDjAMhwQAAAAA +hwR/AAABMA0GCSqGSIb3DQEBBQUAA4IBAQAhy4J0hML3NgmDRHdL5/iTucBe22Mf +jJjg2aifD1S187dHm+Il4qZNO2plWwAhN0h704f+8wpsaALxUvBIu6nvlvcMP5PH +jGN5JLe2Km3UaPvYOQU2SgacLilu+uBcIo2JSHLV6O7ziqUj5Gior6YxDLCtEZie +Ea8aX5/YjuACtEMJ1JjRqjgkM66XAoUe0E8onOK3FgTIO3tGoTJwRp0zS50pFuP0 +PsZtT04ck6mmXEXXknNoAyBCvPypfms9OHqcUIW9fiQnrGbS/Ri4QSQYj0DtFk/1 +na4fY1gf3zTHxH8259b/TOOaPfTnCEsOQtjUrWNR4xhmVZ+HJy4yytUW +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDbzCCAlcCAmm6MA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAlVTMQswCQYD +VQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZMBcGA1UECgwQU3Ryb25n +TG9vcCwgSW5jLjESMBAGA1UECwwJU3Ryb25nT3BzMRowGAYDVQQDDBFjYS5zdHJv +bmdsb29wLmNvbTAeFw0xNTEyMDgyMzM1MzNaFw00MzA0MjQyMzM1MzNaMH0xCzAJ +BgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZ +MBcGA1UECgwQU3Ryb25nTG9vcCwgSW5jLjESMBAGA1UECwwJU3Ryb25nT3BzMRow +GAYDVQQDDBFjYS5zdHJvbmdsb29wLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBANfj86jkvvYDjHBgiqWhk9Cj+bqiMq3MqnV0CBO4iuK33Fo6XssE +H+yVdXlIBFbFe6t655MdBVOR2Sfj7WqNh96vhu6PyDHiwcQlTaiLU6nhIed1J4Wv +lvnJHFmp8Wbtx5AgLT4UYu03ftvXEl2DLi3vhSL2tRM1ebXHB/KPbRWkb25DPX0P +foOHot3f2dgNe2x6kponf7E/QDmAu3s7Nlkfh+ryDhgGU7wocXEhXbprNqRqOGNo +xbXgUI+/9XDxYT/7Gn5LF/fPjtN+aB0SKMnTsDhprVlZie83mlqJ46fOOrR+vrsQ +mi/1m/TadrARtZoIExC/cQRdVM05EK4tUa8CAwEAATANBgkqhkiG9w0BAQsFAAOC +AQEAQ7k5WhyhDTIGYCNzRnrMHWSzGqa1y4tJMW06wafJNRqTm1cthq1ibc6Hfq5a +K10K0qMcgauRTfQ1MWrVCTW/KnJ1vkhiTOH+RvxapGn84gSaRmV6KZen0+gMsgae +KEGe/3Hn+PmDVV+PTamHgPACfpTww38WHIe/7Ce9gHfG7MZ8cKHNZhDy0IAYPln+ +YRwMLd7JNQffHAbWb2CE1mcea4H/12U8JZW5tHCF6y9V+7IuDzqwIrLKcW3lG17n +VUG6ODF/Ryqn3V5X+TL91YyXi6c34y34IpC7MQDV/67U7+5Bp5CfeDPWW2wVSrW+ +uGZtfEvhbNm6m2i4UNmpCXxUZQ== +-----END CERTIFICATE----- +` diff --git a/test/fixtures/nodedir/include/node/config.gypi b/test/fixtures/nodedir/include/node/config.gypi new file mode 100644 index 0000000000..e767534082 --- /dev/null +++ b/test/fixtures/nodedir/include/node/config.gypi @@ -0,0 +1,6 @@ +# Test configuration +{ + 'variables': { + 'build_with_electron': true + } +} diff --git a/test/fixtures/server.crt b/test/fixtures/server.crt deleted file mode 100644 index 5d0c440e07..0000000000 --- a/test/fixtures/server.crt +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYjCCAkoCCQCSlmGR7KzZGTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV -UzELMAkGA1UECAwCQ0ExEDAOBgNVBAoMB05vZGUuanMxETAPBgNVBAsMCG5vZGUt -Z3lwMRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEGJ1aWxkQG5v -ZGVqcy5vcmcwHhcNMTkwNjIyMDYyNTU1WhcNMjkwNjE5MDYyNTU1WjByMQswCQYD -VQQGEwJVUzELMAkGA1UECAwCQ0ExEDAOBgNVBAoMB05vZGUuanMxETAPBgNVBAsM -CG5vZGUtZ3lwMRIwEAYDVQQDDAlsb2NhbGhvc3QxHTAbBgkqhkiG9w0BCQEWDmJ1 -aWxkQGlvanMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6S1E -2WchgmbJYqCnpN7310ZgHjIOqeJe6MpSue2u6z6mTNd5izgvQNaANmn3xLFCS5zs -uZaTvdPYPkcmSQzb1YcZSUYnAxZifjYARc6kb5GSBl3q+O70ELyFrimXfZ4JI+bd -IG9KiHY17DlvZZZj/csGYVWWg0mkeH3O5LPX6/DXQVh/9+gZ02/cdIBCAtZHQwqx -7tF/qZA/kD4GZNFpU1DYHzf9H6g9htoCqmNHQWrV2T9yFybt6mbZp9kglBmyKYCc -7hmQnb7N/mHn1yIuwhBsirCJTfKH86gN81u8M3+SVHA2VUHDllcNhpDWlmInXA+I -tHdGZHCp95ohqpCPgQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCdvYj6CD0ZLwT2 -3t1r+deC3TJuHlNVSeKeT7wIfFnh2FW5riGV0q/w6eXPLTHjuiS6YmpAAbdNUgX/ -sq64FqI2RLpX6pgY5yB0SKopMcJxMLKqmF4zHpIHxtYN5EmN3PR0vehneBR/nZ2T -3ikvWD5JeXlm7Dfw+tjijdxM/sEoDWErGup4mMKMd1s5s830p+ITJUa50d0DLFdH -mqPSbUZF8mMPwGJd+nu1Ht3gTLtK7+gYJgGtXMJmGC0Qg77EJHDB2NbotgDGNmSU -1H9BpAeFHHIcbh2Rr7kkTvnh/c03vFe+CsDZmezcmRpRzW1fKj3YbfqBxU4XwJrL -a5T/N9xU ------END CERTIFICATE----- diff --git a/test/fixtures/server.key b/test/fixtures/server.key deleted file mode 100644 index a8447391e0..0000000000 --- a/test/fixtures/server.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEA6S1E2WchgmbJYqCnpN7310ZgHjIOqeJe6MpSue2u6z6mTNd5 -izgvQNaANmn3xLFCS5zsuZaTvdPYPkcmSQzb1YcZSUYnAxZifjYARc6kb5GSBl3q -+O70ELyFrimXfZ4JI+bdIG9KiHY17DlvZZZj/csGYVWWg0mkeH3O5LPX6/DXQVh/ -9+gZ02/cdIBCAtZHQwqx7tF/qZA/kD4GZNFpU1DYHzf9H6g9htoCqmNHQWrV2T9y -Fybt6mbZp9kglBmyKYCc7hmQnb7N/mHn1yIuwhBsirCJTfKH86gN81u8M3+SVHA2 -VUHDllcNhpDWlmInXA+ItHdGZHCp95ohqpCPgQIDAQABAoIBABW8R4ewalo6dJlB -+n6O3jFt+PW3mtBRLqGqgm2cb0q0a1IMX+MPWLBFjmwEErl+AH0F4rcmBx2Ryr17 -amEy1qcf0caXyHksNAApznqzWXag7iizxnxv4cZRnHBwphNqkNWM5p3oYd04j6w2 -amDg1O9KZozaKo6QZclpiMiezwjKG+PVZLT8p7afswjv+yDWPDByhlcGiye9QD1T -VuZ0QCoXp6N/8JxW0gdkLp9NqFvGeGFzJ5h6L+d7A6BWw8akXrBRHHcKkyvVYBfd -myhSzSK4FPFMaxaEY/65FlVSyAO6ezGm3Umx4g7mkFjLdwKWaIOjkBkPeFgl3Pp4 -7Lo5X3UCgYEA/FrrIwmEU5ayulBVScEMKeavu5eNY4r0Sqbpov2oyTdYe8G49Pzy -ryMXfunY43moLKpajGwgTKRGvdqFtK08AAkaCssiAPkP3rZuZvMTF4sLo/vlWrjP -3er+tUqj22BzXi5XV0BAvH8Y3TL8KQ3he/8JxDvkC811/DQ9Y/Da3U8CgYEA7Itw -UM37URma08Bj9VTMoL9ZCyURewX+ZLDb2+O8sXGXJs28i1RkE6PTBlnRmedn+Jjk -byzQ5Cs5wA5uMbhYTA7kgXOs1bvgQqmlLmyL6FfHkucoMhr2Di7VeGf4OxE26JZ8 -JdY4+1MOyI3A2rR8WU+GmHxy0ay4K2xe6W0vsi8CgYBoGLEKIPDe8jkDtgOYivOT -jT9MaLXALB+dc8DIpU4swpHTaxP6qyUIrbcReTEolJSU6Ci16BxiwRkVU8D3yMYJ -VbfSX/zE3fh37FUaToa/nXHN0SjJBZdpeXhcHE//PIgaf48zxKNvnhYJmPB/luQ+ -m/PRaMsnOzfCM2JniYEe7QKBgGwjnxhB4tgDtaWCue/pcZc3gzS2IJS2e8N6mzie -l6Ajhu+FdOHZldrotUuc+la61OxwsVYmDeWR4VftAPGYDj3PPSX1RRl9R5wSRGLB -2wBASQvew6CMdNqtDIh8N56BUzHnwh/mHKzBHuwO6hDSHFsUITtLAY7bwGKRq55Z -fUmfAoGBANOYFyoJoDLcl+Jd750lyqfCifcGtkRdmZMtrPXaYnD8ZGme9vz1vsK/ -4iUkV3mi7Z9s1LXMa/tPPfKdVhCM1PXost3/si0+u1Bz5yKqEPXlyy2ltpIVyGu8 -yiy7y75asp8Iii/1cgtwyp9+VeSif8wJ+MHQoGdGxvAQP80R3EjF ------END RSA PRIVATE KEY----- diff --git a/test/fixtures/test-charmap.py b/test/fixtures/test-charmap.py index b338f915bc..63aa77bb48 100644 --- a/test/fixtures/test-charmap.py +++ b/test/fixtures/test-charmap.py @@ -1,30 +1,31 @@ -from __future__ import print_function import sys import locale try: - reload(sys) + reload(sys) except NameError: # Python 3 - pass + pass + def main(): - encoding = locale.getdefaultlocale()[1] - if not encoding: - return False + encoding = locale.getdefaultlocale()[1] + if not encoding: + return False - try: - sys.setdefaultencoding(encoding) - except AttributeError: # Python 3 - pass + try: + sys.setdefaultencoding(encoding) + except AttributeError: # Python 3 + pass + + textmap = { + "cp936": "\u4e2d\u6587", + "cp1252": "Lat\u012Bna", + "cp932": "\u306b\u307b\u3093\u3054", + } + if encoding in textmap: + print(textmap[encoding]) + return True - textmap = { - 'cp936': u'\u4e2d\u6587', - 'cp1252': u'Lat\u012Bna', - 'cp932': u'\u306b\u307b\u3093\u3054' - } - if encoding in textmap: - print(textmap[encoding]) - return True -if __name__ == '__main__': - print(main()) +if __name__ == "__main__": + print(main()) diff --git a/test/process-exec-sync.js b/test/process-exec-sync.js index 21763bc26d..0a9002cc80 100644 --- a/test/process-exec-sync.js +++ b/test/process-exec-sync.js @@ -12,7 +12,7 @@ function startsWith (str, search, pos) { } function processExecSync (file, args, options) { - var child, error, timeout, tmpdir, command + let error, command command = makeCommand(file, args) /* @@ -22,10 +22,10 @@ function processExecSync (file, args, options) { options = options || {} // init timeout - timeout = Date.now() + options.timeout + const timeout = Date.now() + options.timeout // init tmpdir - var osTempBase = '/tmp' - var os = determineOS() + let osTempBase = '/tmp' + const os = determineOS() osTempBase = '/tmp' if (process.env.TMP) { @@ -36,7 +36,7 @@ function processExecSync (file, args, options) { osTempBase += '/' } - tmpdir = osTempBase + 'processExecSync.' + Date.now() + Math.random() + const tmpdir = osTempBase + 'processExecSync.' + Date.now() + Math.random() fs.mkdirSync(tmpdir) // init command @@ -49,13 +49,13 @@ function processExecSync (file, args, options) { } // init child - child = childProcess.exec(command, options) + const child = childProcess.exec(command, options) - var maxTry = 100000 // increases the test time by 6 seconds on win-2016-node-0.10 - var tryCount = 0 + const maxTry = 100000 // increases the test time by 6 seconds on win-2016-node-0.10 + let tryCount = 0 while (tryCount < maxTry) { try { - var x = fs.readFileSync(tmpdir + '/status') + const x = fs.readFileSync(tmpdir + '/status') if (x.toString() === '0') { break } @@ -87,10 +87,10 @@ function processExecSync (file, args, options) { } function makeCommand (file, args) { - var command, quote + let command, quote command = file if (args.length > 0) { - for (var i in args) { + for (const i in args) { command = command + ' ' if (args[i][0] === '-') { command = command + args[i] @@ -112,8 +112,8 @@ function makeCommand (file, args) { } function determineOS () { - var os = '' - var tmpVar = '' + let os = '' + let tmpVar = '' if (process.env.OSTYPE) { tmpVar = process.env.OSTYPE } else if (process.env.OS) { diff --git a/test/reporter.js b/test/reporter.js new file mode 100644 index 0000000000..9964b1b5d5 --- /dev/null +++ b/test/reporter.js @@ -0,0 +1,75 @@ +const Mocha = require('mocha') + +class Reporter { + constructor (runner) { + this.failedTests = [] + + runner.on(Mocha.Runner.constants.EVENT_RUN_BEGIN, () => { + console.log('Starting tests') + }) + + runner.on(Mocha.Runner.constants.EVENT_RUN_END, () => { + console.log('Tests finished') + console.log() + console.log('****************') + console.log('* TESTS REPORT *') + console.log('****************') + console.log() + console.log(`Executed ${runner.stats.suites} suites with ${runner.stats.tests} tests in ${runner.stats.duration} ms`) + console.log(` Passed: ${runner.stats.passes}`) + console.log(` Skipped: ${runner.stats.pending}`) + console.log(` Failed: ${runner.stats.failures}`) + if (this.failedTests.length > 0) { + console.log() + console.log(' Failed test details') + this.failedTests.forEach((failedTest, index) => { + console.log() + console.log(` ${index + 1}.'${failedTest.test.fullTitle()}'`) + console.log(` Name: ${failedTest.error.name}`) + console.log(` Message: ${failedTest.error.message}`) + console.log(` Code: ${failedTest.error.code}`) + console.log(` Stack: ${failedTest.error.stack}`) + }) + } + console.log() + }) + + runner.on(Mocha.Runner.constants.EVENT_SUITE_BEGIN, (suite) => { + if (suite.root) { + return + } + console.log(`Starting suite '${suite.title}'`) + }) + + runner.on(Mocha.Runner.constants.EVENT_SUITE_END, (suite) => { + if (suite.root) { + return + } + console.log(`Suite '${suite.title}' finished`) + console.log() + }) + + runner.on(Mocha.Runner.constants.EVENT_TEST_BEGIN, (test) => { + console.log(`Starting test '${test.title}'`) + }) + + runner.on(Mocha.Runner.constants.EVENT_TEST_PASS, (test) => { + console.log(`Test '${test.title}' passed in ${test.duration} ms`) + }) + + runner.on(Mocha.Runner.constants.EVENT_TEST_PENDING, (test) => { + console.log(`Test '${test.title}' skipped in ${test.duration} ms`) + }) + + runner.on(Mocha.Runner.constants.EVENT_TEST_FAIL, (test, error) => { + this.failedTests.push({ test, error }) + console.log(`Test '${test.title}' failed in ${test.duration} ms with ${error}`) + }) + + runner.on(Mocha.Runner.constants.EVENT_TEST_END, (test) => { + console.log() + }) + } +} + +module.exports = Reporter diff --git a/test/simple-proxy.js b/test/simple-proxy.js index cb0dfcfec7..4f8c4137ef 100644 --- a/test/simple-proxy.js +++ b/test/simple-proxy.js @@ -6,7 +6,7 @@ const server = http.createServer(handler) const port = +process.argv[2] const prefix = process.argv[3] const upstream = process.argv[4] -var calls = 0 +let calls = 0 server.listen(port) @@ -15,7 +15,7 @@ function handler (req, res) { throw new Error('request url [' + req.url + '] does not start with [' + prefix + ']') } - var upstreamUrl = upstream + req.url.substring(prefix.length) + const upstreamUrl = upstream + req.url.substring(prefix.length) https.get(upstreamUrl, function (ures) { ures.on('end', function () { if (++calls === 2) { diff --git a/test/test-addon.js b/test/test-addon.js index f79eff73c1..373647dc4c 100644 --- a/test/test-addon.js +++ b/test/test-addon.js @@ -1,6 +1,7 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const path = require('path') const fs = require('graceful-fs') const childProcess = require('child_process') @@ -14,137 +15,138 @@ function runHello (hostProcess) { if (!hostProcess) { hostProcess = process.execPath } - var testCode = "console.log(require('hello_world').hello())" + const testCode = "console.log(require('hello_world').hello())" return execFileSync(hostProcess, ['-e', testCode], { cwd: __dirname }).toString() } function getEncoding () { - var code = 'import locale;print(locale.getdefaultlocale()[1])' + const code = 'import locale;print(locale.getdefaultlocale()[1])' return execFileSync('python', ['-c', code]).toString().trim() } function checkCharmapValid () { - var data + let data try { data = execFileSync('python', ['fixtures/test-charmap.py'], { cwd: __dirname }) } catch (err) { return false } - var lines = data.toString().trim().split('\n') + const lines = data.toString().trim().split('\n') return lines.pop() === 'True' } -test('build simple addon', function (t) { - t.plan(3) - - // Set the loglevel otherwise the output disappears when run via 'npm test' - var cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose'] - var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { - var logLines = stderr.toString().trim().split(/\r?\n/) - var lastLine = logLines[logLines.length - 1] - t.strictEqual(err, null) - t.strictEqual(lastLine, 'gyp info ok', 'should end in ok') - t.strictEqual(runHello().trim(), 'world') +describe('addon', function () { + this.timeout(300000) + + it('build simple addon', function (done) { + // Set the loglevel otherwise the output disappears when run via 'npm test' + const cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose'] + const proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { + const logLines = stderr.toString().trim().split(/\r?\n/) + const lastLine = logLines[logLines.length - 1] + assert.strictEqual(err, null) + assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok') + assert.strictEqual(runHello().trim(), 'world') + done() + }) + proc.stdout.setEncoding('utf-8') + proc.stderr.setEncoding('utf-8') }) - proc.stdout.setEncoding('utf-8') - proc.stderr.setEncoding('utf-8') -}) - -test('build simple addon in path with non-ascii characters', function (t) { - t.plan(1) - if (!checkCharmapValid()) { - return t.skip('python console app can\'t encode non-ascii character.') - } + it('build simple addon in path with non-ascii characters', function (done) { + if (!checkCharmapValid()) { + return this.skip('python console app can\'t encode non-ascii character.') + } - var testDirNames = { - cp936: '文件夹', - cp1252: 'Latīna', - cp932: 'フォルダ' - } - // Select non-ascii characters by current encoding - var testDirName = testDirNames[getEncoding()] - // If encoding is UTF-8 or other then no need to test - if (!testDirName) { - return t.skip('no need to test') - } + const testDirNames = { + cp936: '文件夹', + cp1252: 'Latīna', + cp932: 'フォルダ' + } + // Select non-ascii characters by current encoding + const testDirName = testDirNames[getEncoding()] + // If encoding is UTF-8 or other then no need to test + if (!testDirName) { + return this.skip('no need to test') + } - t.plan(3) + this.timeout(300000) - var data - var configPath = path.join(addonPath, 'build', 'config.gypi') - try { - data = fs.readFileSync(configPath, 'utf8') - } catch (err) { - t.error(err) - return - } - var config = JSON.parse(data.replace(/#.+\n/, '')) - var nodeDir = config.variables.nodedir - var testNodeDir = path.join(addonPath, testDirName) - // Create symbol link to path with non-ascii characters - try { - fs.symlinkSync(nodeDir, testNodeDir, 'dir') - } catch (err) { - switch (err.code) { - case 'EEXIST': break - case 'EPERM': - t.error(err, 'Please try to running console as an administrator') - return - default: - t.error(err) - return + let data + const configPath = path.join(addonPath, 'build', 'config.gypi') + try { + data = fs.readFileSync(configPath, 'utf8') + } catch (err) { + assert.fail(err) + return } - } - - var cmd = [ - nodeGyp, - 'rebuild', - '-C', - addonPath, - '--loglevel=verbose', - '-nodedir=' + testNodeDir - ] - var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { + const config = JSON.parse(data.replace(/#.+\n/, '')) + const nodeDir = config.variables.nodedir + const testNodeDir = path.join(addonPath, testDirName) + // Create symbol link to path with non-ascii characters try { - fs.unlink(testNodeDir) + fs.symlinkSync(nodeDir, testNodeDir, 'dir') } catch (err) { - t.error(err) + switch (err.code) { + case 'EEXIST': break + case 'EPERM': + assert.fail(err, null, 'Please try to running console as an administrator') + return + default: + assert.fail(err) + return + } } - var logLines = stderr.toString().trim().split(/\r?\n/) - var lastLine = logLines[logLines.length - 1] - t.strictEqual(err, null) - t.strictEqual(lastLine, 'gyp info ok', 'should end in ok') - t.strictEqual(runHello().trim(), 'world') + const cmd = [ + nodeGyp, + 'rebuild', + '-C', + addonPath, + '--loglevel=verbose', + '-nodedir=' + testNodeDir + ] + const proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { + try { + fs.unlink(testNodeDir) + } catch (err) { + assert.fail(err) + } + + const logLines = stderr.toString().trim().split(/\r?\n/) + const lastLine = logLines[logLines.length - 1] + assert.strictEqual(err, null) + assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok') + assert.strictEqual(runHello().trim(), 'world') + done() + }) + proc.stdout.setEncoding('utf-8') + proc.stderr.setEncoding('utf-8') }) - proc.stdout.setEncoding('utf-8') - proc.stderr.setEncoding('utf-8') -}) - -test('addon works with renamed host executable', function (t) { - // No `fs.copyFileSync` before node8. - if (process.version.substr(1).split('.')[0] < 8) { - t.skip('skipping test for old node version') - t.end() - return - } - t.plan(3) - - var notNodePath = path.join(os.tmpdir(), 'notnode' + path.extname(process.execPath)) - fs.copyFileSync(process.execPath, notNodePath) + it('addon works with renamed host executable', function (done) { + // No `fs.copyFileSync` before node8. + if (process.version.substr(1).split('.')[0] < 8) { + return this.skip('skipping test for old node version') + } - var cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose'] - var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { - var logLines = stderr.toString().trim().split(/\r?\n/) - var lastLine = logLines[logLines.length - 1] - t.strictEqual(err, null) - t.strictEqual(lastLine, 'gyp info ok', 'should end in ok') - t.strictEqual(runHello(notNodePath).trim(), 'world') - fs.unlinkSync(notNodePath) + this.timeout(300000) + + const notNodePath = path.join(os.tmpdir(), 'notnode' + path.extname(process.execPath)) + fs.copyFileSync(process.execPath, notNodePath) + + const cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose'] + const proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { + const logLines = stderr.toString().trim().split(/\r?\n/) + const lastLine = logLines[logLines.length - 1] + assert.strictEqual(err, null) + assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok') + assert.strictEqual(runHello(notNodePath).trim(), 'world') + fs.unlinkSync(notNodePath) + done() + }) + proc.stdout.setEncoding('utf-8') + proc.stderr.setEncoding('utf-8') }) - proc.stdout.setEncoding('utf-8') - proc.stderr.setEncoding('utf-8') }) diff --git a/test/test-configure-python.js b/test/test-configure-python.js index ac25f7972e..dcce3e5de2 100644 --- a/test/test-configure-python.js +++ b/test/test-configure-python.js @@ -1,9 +1,11 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const path = require('path') const devDir = require('./common').devDir() const gyp = require('../lib/node-gyp') +const log = require('../lib/log') const requireInject = require('require-inject') const configure = requireInject('../lib/configure', { 'graceful-fs': { @@ -11,69 +13,68 @@ const configure = requireInject('../lib/configure', { closeSync: function () { }, writeFile: function (file, data, cb) { cb() }, stat: function (file, cb) { cb(null, {}) }, - mkdir: function (dir, options, cb) { cb() } + mkdir: function (dir, options, cb) { cb() }, + promises: { + writeFile: function (file, data) { return Promise.resolve(null) } + } } }) +log.logger.stream = null + const EXPECTED_PYPATH = path.join(__dirname, '..', 'gyp', 'pylib') const SEPARATOR = process.platform === 'win32' ? ';' : ':' -const SPAWN_RESULT = { on: function () { } } - -require('npmlog').level = 'warn' - -test('configure PYTHONPATH with no existing env', function (t) { - t.plan(1) - - delete process.env.PYTHONPATH - - var prog = gyp() - prog.parseArgv([]) - prog.spawn = function () { - t.equal(process.env.PYTHONPATH, EXPECTED_PYPATH) - return SPAWN_RESULT - } - prog.devDir = devDir - configure(prog, [], t.fail) -}) - -test('configure PYTHONPATH with existing env of one dir', function (t) { - t.plan(2) - - var existingPath = path.join('a', 'b') - process.env.PYTHONPATH = existingPath - - var prog = gyp() - prog.parseArgv([]) - prog.spawn = function () { - t.equal(process.env.PYTHONPATH, [EXPECTED_PYPATH, existingPath].join(SEPARATOR)) - - var dirs = process.env.PYTHONPATH.split(SEPARATOR) - t.deepEqual(dirs, [EXPECTED_PYPATH, existingPath]) - - return SPAWN_RESULT - } - prog.devDir = devDir - configure(prog, [], t.fail) -}) - -test('configure PYTHONPATH with existing env of multiple dirs', function (t) { - t.plan(2) - - var pythonDir1 = path.join('a', 'b') - var pythonDir2 = path.join('b', 'c') - var existingPath = [pythonDir1, pythonDir2].join(SEPARATOR) - process.env.PYTHONPATH = existingPath - - var prog = gyp() - prog.parseArgv([]) - prog.spawn = function () { - t.equal(process.env.PYTHONPATH, [EXPECTED_PYPATH, existingPath].join(SEPARATOR)) - - var dirs = process.env.PYTHONPATH.split(SEPARATOR) - t.deepEqual(dirs, [EXPECTED_PYPATH, pythonDir1, pythonDir2]) - - return SPAWN_RESULT - } - prog.devDir = devDir - configure(prog, [], t.fail) +const SPAWN_RESULT = cb => ({ on: function () { cb() } }) + +describe('configure-python', function () { + it('configure PYTHONPATH with no existing env', function (done) { + delete process.env.PYTHONPATH + + const prog = gyp() + prog.parseArgv([]) + prog.spawn = function () { + assert.strictEqual(process.env.PYTHONPATH, EXPECTED_PYPATH) + return SPAWN_RESULT(done) + } + prog.devDir = devDir + configure(prog, [], assert.fail) + }) + + it('configure PYTHONPATH with existing env of one dir', function (done) { + const existingPath = path.join('a', 'b') + process.env.PYTHONPATH = existingPath + + const prog = gyp() + prog.parseArgv([]) + prog.spawn = function () { + assert.strictEqual(process.env.PYTHONPATH, [EXPECTED_PYPATH, existingPath].join(SEPARATOR)) + + const dirs = process.env.PYTHONPATH.split(SEPARATOR) + assert.deepStrictEqual(dirs, [EXPECTED_PYPATH, existingPath]) + + return SPAWN_RESULT(done) + } + prog.devDir = devDir + configure(prog, [], assert.fail) + }) + + it('configure PYTHONPATH with existing env of multiple dirs', function (done) { + const pythonDir1 = path.join('a', 'b') + const pythonDir2 = path.join('b', 'c') + const existingPath = [pythonDir1, pythonDir2].join(SEPARATOR) + process.env.PYTHONPATH = existingPath + + const prog = gyp() + prog.parseArgv([]) + prog.spawn = function () { + assert.strictEqual(process.env.PYTHONPATH, [EXPECTED_PYPATH, existingPath].join(SEPARATOR)) + + const dirs = process.env.PYTHONPATH.split(SEPARATOR) + assert.deepStrictEqual(dirs, [EXPECTED_PYPATH, pythonDir1, pythonDir2]) + + return SPAWN_RESULT(done) + } + prog.devDir = devDir + configure(prog, [], assert.fail) + }) }) diff --git a/test/test-create-config-gypi.js b/test/test-create-config-gypi.js new file mode 100644 index 0000000000..725819b6aa --- /dev/null +++ b/test/test-create-config-gypi.js @@ -0,0 +1,61 @@ +'use strict' + +const path = require('path') +const { describe, it } = require('mocha') +const assert = require('assert') +const gyp = require('../lib/node-gyp') +const createConfigGypi = require('../lib/create-config-gypi') +const { parseConfigGypi, getCurrentConfigGypi } = createConfigGypi.test + +describe('create-config-gypi', function () { + it('config.gypi with no options', async function () { + const prog = gyp() + prog.parseArgv([]) + + const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} }) + assert.strictEqual(config.target_defaults.default_configuration, 'Release') + assert.strictEqual(config.variables.target_arch, process.arch) + }) + + it('config.gypi with --debug', async function () { + const prog = gyp() + prog.parseArgv(['_', '_', '--debug']) + + const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} }) + assert.strictEqual(config.target_defaults.default_configuration, 'Debug') + }) + + it('config.gypi with custom options', async function () { + const prog = gyp() + prog.parseArgv(['_', '_', '--shared-libxml2']) + + const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} }) + assert.strictEqual(config.variables.shared_libxml2, true) + }) + + it('config.gypi with nodedir', async function () { + const nodeDir = path.join(__dirname, 'fixtures', 'nodedir') + + const prog = gyp() + prog.parseArgv(['_', '_', `--nodedir=${nodeDir}`]) + + const config = await getCurrentConfigGypi({ gyp: prog, nodeDir, vsInfo: {} }) + assert.strictEqual(config.variables.build_with_electron, true) + }) + + it('config.gypi with --force-process-config', async function () { + const nodeDir = path.join(__dirname, 'fixtures', 'nodedir') + + const prog = gyp() + prog.parseArgv(['_', '_', '--force-process-config', `--nodedir=${nodeDir}`]) + + const config = await getCurrentConfigGypi({ gyp: prog, nodeDir, vsInfo: {} }) + assert.strictEqual(config.variables.build_with_electron, undefined) + }) + + it('config.gypi parsing', function () { + const str = "# Some comments\n{'variables': {'multiline': 'A'\n'B'}}" + const config = parseConfigGypi(str) + assert.deepStrictEqual(config, { variables: { multiline: 'AB' } }) + }) +}) diff --git a/test/test-download.js b/test/test-download.js index fe373e3280..0a13df520b 100644 --- a/test/test-download.js +++ b/test/test-download.js @@ -1,268 +1,209 @@ 'use strict' -const test = require('tap').test -const fs = require('fs') +const { describe, it, after } = require('mocha') +const assert = require('assert') +const fs = require('fs/promises') const path = require('path') +const util = require('util') const http = require('http') const https = require('https') const install = require('../lib/install') const semver = require('semver') const devDir = require('./common').devDir() -const rimraf = require('rimraf') const gyp = require('../lib/node-gyp') -const log = require('npmlog') +const log = require('../lib/log') +const certs = require('./fixtures/certs') -log.level = 'warn' +log.logger.stream = null -test('download over http', function (t) { - t.plan(2) +describe('download', function () { + it('download over http', async function () { + const server = http.createServer((req, res) => { + assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) + res.end('ok') + }) - var server = http.createServer(function (req, res) { - t.strictEqual(req.headers['user-agent'], - 'node-gyp v42 (node ' + process.version + ')') - res.end('ok') - server.close() - }) + after(() => new Promise((resolve) => server.close(resolve))) - var host = 'localhost' - server.listen(0, host, function () { - var port = this.address().port - var gyp = { + const host = 'localhost' + await new Promise((resolve) => server.listen(0, host, resolve)) + const { port } = server.address() + const gyp = { opts: {}, version: '42' } - var url = 'http://' + host + ':' + port - var req = install.test.download(gyp, {}, url) - req.on('response', function (res) { - var body = '' - res.setEncoding('utf8') - res.on('data', function (data) { - body += data - }) - res.on('end', function () { - t.strictEqual(body, 'ok') - }) - }) + const url = `http://${host}:${port}` + const res = await install.test.download(gyp, url) + assert.strictEqual(await res.text(), 'ok') }) -}) -test('download over https with custom ca', function (t) { - t.plan(3) + it('download over https with custom ca', async function () { + const cafile = path.join(__dirname, 'fixtures/ca.crt') + const cacontents = certs['ca.crt'] + const cert = certs['server.crt'] + const key = certs['server.key'] + await fs.writeFile(cafile, cacontents, 'utf8') + const ca = await install.test.readCAFile(cafile) - var cert = fs.readFileSync(path.join(__dirname, 'fixtures/server.crt'), 'utf8') - var key = fs.readFileSync(path.join(__dirname, 'fixtures/server.key'), 'utf8') + assert.strictEqual(ca.length, 1) - var cafile = path.join(__dirname, '/fixtures/ca.crt') - var ca = install.test.readCAFile(cafile) - t.strictEqual(ca.length, 1) + const options = { ca, cert, key } + const server = https.createServer(options, (req, res) => { + assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) + res.end('ok') + }) - var options = { ca: ca, cert: cert, key: key } - var server = https.createServer(options, function (req, res) { - t.strictEqual(req.headers['user-agent'], - 'node-gyp v42 (node ' + process.version + ')') - res.end('ok') - server.close() - }) + after(async () => { + await new Promise((resolve) => server.close(resolve)) + await fs.unlink(cafile) + }) - server.on('clientError', function (err) { - throw err - }) + server.on('clientError', (err) => { throw err }) - var host = 'localhost' - server.listen(8000, host, function () { - var port = this.address().port - var gyp = { - opts: { cafile: cafile }, + const host = 'localhost' + await new Promise((resolve) => server.listen(0, host, resolve)) + const { port } = server.address() + const gyp = { + opts: { cafile }, version: '42' } - var url = 'https://' + host + ':' + port - var req = install.test.download(gyp, {}, url) - req.on('response', function (res) { - var body = '' - res.setEncoding('utf8') - res.on('data', function (data) { - body += data - }) - res.on('end', function () { - t.strictEqual(body, 'ok') - }) - }) + const url = `https://${host}:${port}` + const res = await install.test.download(gyp, url) + assert.strictEqual(await res.text(), 'ok') }) -}) -test('download over http with proxy', function (t) { - t.plan(2) - - var server = http.createServer(function (req, res) { - t.strictEqual(req.headers['user-agent'], - 'node-gyp v42 (node ' + process.version + ')') - res.end('ok') - pserver.close(function () { - server.close() + it('download over http with proxy', async function () { + const server = http.createServer((_, res) => { + res.end('ok') }) - }) - var pserver = http.createServer(function (req, res) { - t.strictEqual(req.headers['user-agent'], - 'node-gyp v42 (node ' + process.version + ')') - res.end('proxy ok') - server.close(function () { - pserver.close() + const pserver = http.createServer((req, res) => { + assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) + res.end('proxy ok') }) - }) - var host = 'localhost' - server.listen(0, host, function () { - var port = this.address().port - pserver.listen(port + 1, host, function () { - var gyp = { - opts: { - proxy: 'http://' + host + ':' + (port + 1) - }, - version: '42' - } - var url = 'http://' + host + ':' + port - var req = install.test.download(gyp, {}, url) - req.on('response', function (res) { - var body = '' - res.setEncoding('utf8') - res.on('data', function (data) { - body += data - }) - res.on('end', function () { - t.strictEqual(body, 'proxy ok') - }) - }) - }) + after(() => Promise.all([ + new Promise((resolve) => server.close(resolve)), + new Promise((resolve) => pserver.close(resolve)) + ])) + + const host = 'localhost' + await new Promise((resolve) => server.listen(0, host, resolve)) + const { port } = server.address() + await new Promise((resolve) => pserver.listen(port + 1, host, resolve)) + const gyp = { + opts: { + proxy: `http://${host}:${port + 1}`, + noproxy: 'bad' + }, + version: '42' + } + const url = `http://${host}:${port}` + const res = await install.test.download(gyp, url) + assert.strictEqual(await res.text(), 'proxy ok') }) -}) -test('download over http with noproxy', function (t) { - t.plan(2) + it('download over http with noproxy', async function () { + const server = http.createServer((req, res) => { + assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) + res.end('ok') + }) - var server = http.createServer(function (req, res) { - t.strictEqual(req.headers['user-agent'], - 'node-gyp v42 (node ' + process.version + ')') - res.end('ok') - pserver.close(function () { - server.close() + const pserver = http.createServer((_, res) => { + res.end('proxy ok') }) + + after(() => Promise.all([ + new Promise((resolve) => server.close(resolve)), + new Promise((resolve) => pserver.close(resolve)) + ])) + + const host = 'localhost' + await new Promise((resolve) => server.listen(0, host, resolve)) + const { port } = server.address() + await new Promise((resolve) => pserver.listen(port + 1, host, resolve)) + const gyp = { + opts: { + proxy: `http://${host}:${port + 1}`, + noproxy: host + }, + version: '42' + } + const url = `http://${host}:${port}` + const res = await install.test.download(gyp, url) + assert.strictEqual(await res.text(), 'ok') }) - var pserver = http.createServer(function (req, res) { - t.strictEqual(req.headers['user-agent'], - 'node-gyp v42 (node ' + process.version + ')') - res.end('proxy ok') - server.close(function () { - pserver.close() - }) + it('download with missing cafile', async function () { + const gyp = { + opts: { cafile: 'no.such.file' } + } + try { + await install.test.download(gyp, {}, 'http://bad/') + } catch (e) { + assert.ok(/no.such.file/.test(e.message)) + } }) - var host = 'localhost' - server.listen(0, host, function () { - var port = this.address().port - pserver.listen(port + 1, host, function () { - var gyp = { - opts: { - proxy: 'http://' + host + ':' + (port + 1), - noproxy: 'localhost' - }, - version: '42' - } - var url = 'http://' + host + ':' + port - var req = install.test.download(gyp, {}, url) - req.on('response', function (res) { - var body = '' - res.setEncoding('utf8') - res.on('data', function (data) { - body += data - }) - res.on('end', function () { - t.strictEqual(body, 'ok') - }) - }) + it('check certificate splitting', async function () { + const cafile = path.join(__dirname, 'fixtures/ca-bundle.crt') + const cacontents = certs['ca-bundle.crt'] + await fs.writeFile(cafile, cacontents, 'utf8') + after(async () => { + await fs.unlink(cafile) }) + const cas = await install.test.readCAFile(path.join(__dirname, 'fixtures/ca-bundle.crt')) + assert.strictEqual(cas.length, 2) + assert.notStrictEqual(cas[0], cas[1]) }) -}) - -test('download with missing cafile', function (t) { - t.plan(1) - var gyp = { - opts: { cafile: 'no.such.file' } - } - try { - install.test.download(gyp, {}, 'http://bad/') - } catch (e) { - t.ok(/no.such.file/.test(e.message)) - } -}) - -test('check certificate splitting', function (t) { - var cas = install.test.readCAFile(path.join(__dirname, 'fixtures/ca-bundle.crt')) - t.plan(2) - t.strictEqual(cas.length, 2) - t.notStrictEqual(cas[0], cas[1]) -}) -// only run this test if we are running a version of Node with predictable version path behavior + // only run this test if we are running a version of Node with predictable version path behavior -test('download headers (actual)', function (t) { - if (process.env.FAST_TEST || - process.release.name !== 'node' || - semver.prerelease(process.version) !== null || - semver.satisfies(process.version, '<10')) { - return t.skip('Skipping actual download of headers due to test environment configuration') - } + it('download headers (actual)', async function () { + if (process.env.FAST_TEST || + process.release.name !== 'node' || + semver.prerelease(process.version) !== null || + semver.satisfies(process.version, '<10')) { + return this.skip('Skipping actual download of headers due to test environment configuration') + } - t.plan(17) + this.timeout(300000) - const expectedDir = path.join(devDir, process.version.replace(/^v/, '')) - rimraf(expectedDir, (err) => { - t.ifError(err) + const expectedDir = path.join(devDir, process.version.replace(/^v/, '')) + await fs.rm(expectedDir, { recursive: true, force: true }) const prog = gyp() prog.parseArgv([]) prog.devDir = devDir log.level = 'warn' - install(prog, [], (err) => { - t.ifError(err) - - fs.readFile(path.join(expectedDir, 'installVersion'), 'utf8', (err, data) => { - t.ifError(err) - t.strictEqual(data, '9\n', 'correct installVersion') - }) - - fs.readdir(path.join(expectedDir, 'include/node'), (err, list) => { - t.ifError(err) - - t.ok(list.includes('common.gypi')) - t.ok(list.includes('config.gypi')) - t.ok(list.includes('node.h')) - t.ok(list.includes('node_version.h')) - t.ok(list.includes('openssl')) - t.ok(list.includes('uv')) - t.ok(list.includes('uv.h')) - t.ok(list.includes('v8-platform.h')) - t.ok(list.includes('v8.h')) - t.ok(list.includes('zlib.h')) - }) - - fs.readFile(path.join(expectedDir, 'include/node/node_version.h'), 'utf8', (err, contents) => { - t.ifError(err) - - const lines = contents.split('\n') - - // extract the 3 version parts from the defines to build a valid version string and - // and check them against our current env version - const version = ['major', 'minor', 'patch'].reduce((version, type) => { - const re = new RegExp(`^#define\\sNODE_${type.toUpperCase()}_VERSION`) - const line = lines.find((l) => re.test(l)) - const i = line ? parseInt(line.replace(/^[^0-9]+([0-9]+).*$/, '$1'), 10) : 'ERROR' - return `${version}${type !== 'major' ? '.' : 'v'}${i}` - }, '') - - t.strictEqual(version, process.version) - }) - }) + await util.promisify(install)(prog, []) + + const data = await fs.readFile(path.join(expectedDir, 'installVersion'), 'utf8') + assert.strictEqual(data, '11\n', 'correct installVersion') + + const list = await fs.readdir(path.join(expectedDir, 'include/node')) + assert.ok(list.includes('common.gypi')) + assert.ok(list.includes('config.gypi')) + assert.ok(list.includes('node.h')) + assert.ok(list.includes('node_version.h')) + assert.ok(list.includes('openssl')) + assert.ok(list.includes('uv')) + assert.ok(list.includes('uv.h')) + assert.ok(list.includes('v8-platform.h')) + assert.ok(list.includes('v8.h')) + assert.ok(list.includes('zlib.h')) + + const lines = (await fs.readFile(path.join(expectedDir, 'include/node/node_version.h'), 'utf8')).split('\n') + + // extract the 3 version parts from the defines to build a valid version string and + // and check them against our current env version + const version = ['major', 'minor', 'patch'].reduce((version, type) => { + const re = new RegExp(`^#define\\sNODE_${type.toUpperCase()}_VERSION`) + const line = lines.find((l) => re.test(l)) + const i = line ? parseInt(line.replace(/^[^0-9]+([0-9]+).*$/, '$1'), 10) : 'ERROR' + return `${version}${type !== 'major' ? '.' : 'v'}${i}` + }, '') + + assert.strictEqual(version, process.version) }) }) diff --git a/test/test-find-accessible-sync.js b/test/test-find-accessible-sync.js index 0a2e584c4f..9ec12dbb33 100644 --- a/test/test-find-accessible-sync.js +++ b/test/test-find-accessible-sync.js @@ -1,6 +1,7 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const path = require('path') const requireInject = require('require-inject') const configure = requireInject('../lib/configure', { @@ -10,7 +11,7 @@ const configure = requireInject('../lib/configure', { if (readableFiles.some(function (f) { return f === path })) { return 0 } else { - var error = new Error('ENOENT - not found') + const error = new Error('ENOENT - not found') throw error } } @@ -27,58 +28,46 @@ const readableFiles = [ path.resolve(dir, readableFileInDir) ] -test('find accessible - empty array', function (t) { - t.plan(1) - - var candidates = [] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, undefined) -}) - -test('find accessible - single item array, readable', function (t) { - t.plan(1) - - var candidates = [readableFile] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, path.resolve(dir, readableFile)) -}) - -test('find accessible - single item array, readable in subdir', function (t) { - t.plan(1) - - var candidates = [readableFileInDir] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, path.resolve(dir, readableFileInDir)) -}) - -test('find accessible - single item array, unreadable', function (t) { - t.plan(1) - - var candidates = ['unreadable_file'] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, undefined) -}) - -test('find accessible - multi item array, no matches', function (t) { - t.plan(1) - - var candidates = ['non_existent_file', 'unreadable_file'] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, undefined) -}) - -test('find accessible - multi item array, single match', function (t) { - t.plan(1) - - var candidates = ['non_existent_file', readableFile] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, path.resolve(dir, readableFile)) -}) - -test('find accessible - multi item array, return first match', function (t) { - t.plan(1) - - var candidates = ['non_existent_file', anotherReadableFile, readableFile] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, path.resolve(dir, anotherReadableFile)) +describe('find-accessible-sync', function () { + it('find accessible - empty array', function () { + const candidates = [] + const found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, undefined) + }) + + it('find accessible - single item array, readable', function () { + const candidates = [readableFile] + const found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, path.resolve(dir, readableFile)) + }) + + it('find accessible - single item array, readable in subdir', function () { + const candidates = [readableFileInDir] + const found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, path.resolve(dir, readableFileInDir)) + }) + + it('find accessible - single item array, unreadable', function () { + const candidates = ['unreadable_file'] + const found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, undefined) + }) + + it('find accessible - multi item array, no matches', function () { + const candidates = ['non_existent_file', 'unreadable_file'] + const found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, undefined) + }) + + it('find accessible - multi item array, single match', function () { + const candidates = ['non_existent_file', readableFile] + const found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, path.resolve(dir, readableFile)) + }) + + it('find accessible - multi item array, return first match', function () { + const candidates = ['non_existent_file', anotherReadableFile, readableFile] + const found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, path.resolve(dir, anotherReadableFile)) + }) }) diff --git a/test/test-find-node-directory.js b/test/test-find-node-directory.js index f1380d162a..e36a5c04ea 100644 --- a/test/test-find-node-directory.js +++ b/test/test-find-node-directory.js @@ -1,119 +1,115 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const path = require('path') const findNodeDirectory = require('../lib/find-node-directory') -const platforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32', 'aix'] +const platforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32', 'aix', 'os400'] -// we should find the directory based on the directory -// the script is running in and it should match the layout -// in a build tree where npm is installed in -// .... /deps/npm -test('test find-node-directory - node install', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } - t.equal( - findNodeDirectory('/x/deps/npm/node_modules/node-gyp/lib', processObj), - path.join('/x')) - } -}) +describe('find-node-directory', function () { + // we should find the directory based on the directory + // the script is running in and it should match the layout + // in a build tree where npm is installed in + // .... /deps/npm + it('test find-node-directory - node install', function () { + for (let next = 0; next < platforms.length; next++) { + const processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } + assert.strictEqual( + findNodeDirectory('/x/deps/npm/node_modules/node-gyp/lib', processObj), + path.join('/x')) + } + }) -// we should find the directory based on the directory -// the script is running in and it should match the layout -// in an installed tree where npm is installed in -// .... /lib/node_modules/npm or .../node_modules/npm -// depending on the patform -test('test find-node-directory - node build', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } - if (platforms[next] === 'win32') { - t.equal( - findNodeDirectory('/y/node_modules/npm/node_modules/node-gyp/lib', - processObj), path.join('/y')) - } else { - t.equal( - findNodeDirectory('/y/lib/node_modules/npm/node_modules/node-gyp/lib', - processObj), path.join('/y')) + // we should find the directory based on the directory + // the script is running in and it should match the layout + // in an installed tree where npm is installed in + // .... /lib/node_modules/npm or .../node_modules/npm + // depending on the patform + it('test find-node-directory - node build', function () { + for (let next = 0; next < platforms.length; next++) { + const processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } + if (platforms[next] === 'win32') { + assert.strictEqual( + findNodeDirectory('/y/node_modules/npm/node_modules/node-gyp/lib', + processObj), path.join('/y')) + } else { + assert.strictEqual( + findNodeDirectory('/y/lib/node_modules/npm/node_modules/node-gyp/lib', + processObj), path.join('/y')) + } } - } -}) + }) -// we should find the directory based on the execPath -// for node and match because it was in the bin directory -test('test find-node-directory - node in bin directory', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } - t.equal( - findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), - path.join('/x/y')) - } -}) + // we should find the directory based on the execPath + // for node and match because it was in the bin directory + it('test find-node-directory - node in bin directory', function () { + for (let next = 0; next < platforms.length; next++) { + const processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } + assert.strictEqual( + findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), + path.join('/x/y')) + } + }) -// we should find the directory based on the execPath -// for node and match because it was in the Release directory -test('test find-node-directory - node in build release dir', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj - if (platforms[next] === 'win32') { - processObj = { execPath: '/x/y/Release/node', platform: platforms[next] } - } else { - processObj = { - execPath: '/x/y/out/Release/node', - platform: platforms[next] + // we should find the directory based on the execPath + // for node and match because it was in the Release directory + it('test find-node-directory - node in build release dir', function () { + for (let next = 0; next < platforms.length; next++) { + let processObj + if (platforms[next] === 'win32') { + processObj = { execPath: '/x/y/Release/node', platform: platforms[next] } + } else { + processObj = { + execPath: '/x/y/out/Release/node', + platform: platforms[next] + } } + + assert.strictEqual( + findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), + path.join('/x/y')) } + }) - t.equal( - findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), - path.join('/x/y')) - } -}) + // we should find the directory based on the execPath + // for node and match because it was in the Debug directory + it('test find-node-directory - node in Debug release dir', function () { + for (let next = 0; next < platforms.length; next++) { + let processObj + if (platforms[next] === 'win32') { + processObj = { execPath: '/a/b/Debug/node', platform: platforms[next] } + } else { + processObj = { execPath: '/a/b/out/Debug/node', platform: platforms[next] } + } -// we should find the directory based on the execPath -// for node and match because it was in the Debug directory -test('test find-node-directory - node in Debug release dir', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj - if (platforms[next] === 'win32') { - processObj = { execPath: '/a/b/Debug/node', platform: platforms[next] } - } else { - processObj = { execPath: '/a/b/out/Debug/node', platform: platforms[next] } + assert.strictEqual( + findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), + path.join('/a/b')) } + }) - t.equal( - findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), - path.join('/a/b')) - } -}) - -// we should not find it as it will not match based on the execPath nor -// the directory from which the script is running -test('test find-node-directory - not found', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj = { execPath: '/x/y/z/y', platform: next } - t.equal(findNodeDirectory('/a/b/c/d', processObj), '') - } -}) + // we should not find it as it will not match based on the execPath nor + // the directory from which the script is running + it('test find-node-directory - not found', function () { + for (let next = 0; next < platforms.length; next++) { + const processObj = { execPath: '/x/y/z/y', platform: next } + assert.strictEqual(findNodeDirectory('/a/b/c/d', processObj), '') + } + }) -// we should find the directory based on the directory -// the script is running in and it should match the layout -// in a build tree where npm is installed in -// .... /deps/npm -// same test as above but make sure additional directory entries -// don't cause an issue -test('test find-node-directory - node install', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } - t.equal( - findNodeDirectory('/x/y/z/a/b/c/deps/npm/node_modules/node-gyp/lib', - processObj), path.join('/x/y/z/a/b/c')) - } + // we should find the directory based on the directory + // the script is running in and it should match the layout + // in a build tree where npm is installed in + // .... /deps/npm + // same test as above but make sure additional directory entries + // don't cause an issue + it('test find-node-directory - node install', function () { + for (let next = 0; next < platforms.length; next++) { + const processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } + assert.strictEqual( + findNodeDirectory('/x/y/z/a/b/c/deps/npm/node_modules/node-gyp/lib', + processObj), path.join('/x/y/z/a/b/c')) + } + }) }) diff --git a/test/test-find-python.js b/test/test-find-python.js index 6be887f7eb..e1880bea7a 100644 --- a/test/test-find-python.js +++ b/test/test-find-python.js @@ -2,229 +2,202 @@ delete process.env.PYTHON -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const findPython = require('../lib/find-python') const execFile = require('child_process').execFile const PythonFinder = findPython.test.PythonFinder -require('npmlog').level = 'warn' - -test('find python', function (t) { - t.plan(4) - - findPython.test.findPython(null, function (err, found) { - t.strictEqual(err, null) - var proc = execFile(found, ['-V'], function (err, stdout, stderr) { - t.strictEqual(err, null) - if (/Python 2/.test(stderr)) { - t.strictEqual(stdout, '') - t.ok(/Python 2/.test(stderr)) - } else { - t.ok(/Python 3/.test(stdout)) - t.strictEqual(stderr, '') - } +describe('find-python', function () { + it('find python', function () { + findPython.test.findPython(null, function (err, found) { + assert.strictEqual(err, null) + const proc = execFile(found, ['-V'], function (err, stdout, stderr) { + assert.strictEqual(err, null) + assert.ok(/Python 3/.test(stdout)) + assert.strictEqual(stderr, '') + }) + proc.stdout.setEncoding('utf-8') + proc.stderr.setEncoding('utf-8') }) - proc.stdout.setEncoding('utf-8') - proc.stderr.setEncoding('utf-8') }) -}) -function poison (object, property) { - function fail () { - console.error(Error(`Property ${property} should not have been accessed.`)) - process.abort() - } - var descriptor = { - configurable: false, - enumerable: false, - get: fail, - set: fail - } - Object.defineProperty(object, property, descriptor) -} - -function TestPythonFinder () { - PythonFinder.apply(this, arguments) -} -TestPythonFinder.prototype = Object.create(PythonFinder.prototype) -// Silence npmlog - remove for debugging -TestPythonFinder.prototype.log = { - silly: () => {}, - verbose: () => {}, - info: () => {}, - warn: () => {}, - error: () => {} -} -delete TestPythonFinder.prototype.env.NODE_GYP_FORCE_PYTHON - -test('find python - python', function (t) { - t.plan(6) - - var f = new TestPythonFinder('python', done) - f.execFile = function (program, args, opts, cb) { - f.execFile = function (program, args, opts, cb) { - poison(f, 'execFile') - t.strictEqual(program, '/path/python') - t.ok(/sys\.version_info/.test(args[1])) - cb(null, '2.7.15') - } - t.strictEqual(program, - process.platform === 'win32' ? '"python"' : 'python') - t.ok(/sys\.executable/.test(args[1])) - cb(null, '/path/python') + function poison (object, property) { + function fail () { + console.error(Error(`Property ${property} should not have been accessed.`)) + process.abort() + } + const descriptor = { + configurable: false, + enumerable: false, + get: fail, + set: fail + } + Object.defineProperty(object, property, descriptor) } - f.findPython() - function done (err, python) { - t.strictEqual(err, null) - t.strictEqual(python, '/path/python') + function TestPythonFinder () { + PythonFinder.apply(this, arguments) } -}) - -test('find python - python too old', function (t) { - t.plan(2) + TestPythonFinder.prototype = Object.create(PythonFinder.prototype) + delete TestPythonFinder.prototype.env.NODE_GYP_FORCE_PYTHON - var f = new TestPythonFinder(null, done) - f.execFile = function (program, args, opts, cb) { - if (/sys\.executable/.test(args[args.length - 1])) { + it('find python - python', function () { + const f = new TestPythonFinder('python', done) + f.execFile = function (program, args, opts, cb) { + f.execFile = function (program, args, opts, cb) { + poison(f, 'execFile') + assert.strictEqual(program, '/path/python') + assert.ok(/sys\.version_info/.test(args[1])) + cb(null, '3.9.1') + } + assert.strictEqual(program, + process.platform === 'win32' ? '"python"' : 'python') + assert.ok(/sys\.executable/.test(args[1])) cb(null, '/path/python') - } else if (/sys\.version_info/.test(args[args.length - 1])) { - cb(null, '2.3.4') - } else { - t.fail() } - } - f.findPython() + f.findPython() - function done (err) { - t.ok(/Could not find any Python/.test(err)) - t.ok(/not supported/i.test(f.errorLog)) - } -}) + function done (err, python) { + assert.strictEqual(err, null) + assert.strictEqual(python, '/path/python') + } + }) -test('find python - no python', function (t) { - t.plan(2) + it('find python - python too old', function () { + const f = new TestPythonFinder(null, done) + f.execFile = function (program, args, opts, cb) { + if (/sys\.executable/.test(args[args.length - 1])) { + cb(null, '/path/python') + } else if (/sys\.version_info/.test(args[args.length - 1])) { + cb(null, '2.3.4') + } else { + assert.fail() + } + } + f.findPython() - var f = new TestPythonFinder(null, done) - f.execFile = function (program, args, opts, cb) { - if (/sys\.executable/.test(args[args.length - 1])) { - cb(new Error('not found')) - } else if (/sys\.version_info/.test(args[args.length - 1])) { - cb(new Error('not a Python executable')) - } else { - t.fail() + function done (err) { + assert.ok(/Could not find any Python/.test(err)) + assert.ok(/not supported/i.test(f.errorLog)) } - } - f.findPython() + }) - function done (err) { - t.ok(/Could not find any Python/.test(err)) - t.ok(/not in PATH/.test(f.errorLog)) - } -}) + it('find python - no python', function () { + const f = new TestPythonFinder(null, done) + f.execFile = function (program, args, opts, cb) { + if (/sys\.executable/.test(args[args.length - 1])) { + cb(new Error('not found')) + } else if (/sys\.version_info/.test(args[args.length - 1])) { + cb(new Error('not a Python executable')) + } else { + assert.fail() + } + } + f.findPython() -test('find python - no python2, no python, unix', function (t) { - t.plan(2) + function done (err) { + assert.ok(/Could not find any Python/.test(err)) + assert.ok(/not in PATH/.test(f.errorLog)) + } + }) - var f = new TestPythonFinder(null, done) - f.checkPyLauncher = t.fail - f.win = false + it('find python - no python2, no python, unix', function () { + const f = new TestPythonFinder(null, done) + f.checkPyLauncher = assert.fail + f.win = false - f.execFile = function (program, args, opts, cb) { - if (/sys\.executable/.test(args[args.length - 1])) { - cb(new Error('not found')) - } else { - t.fail() + f.execFile = function (program, args, opts, cb) { + if (/sys\.executable/.test(args[args.length - 1])) { + cb(new Error('not found')) + } else { + assert.fail() + } } - } - f.findPython() - - function done (err) { - t.ok(/Could not find any Python/.test(err)) - t.ok(/not in PATH/.test(f.errorLog)) - } -}) + f.findPython() -test('find python - no python, use python launcher', function (t) { - t.plan(3) + function done (err) { + assert.ok(/Could not find any Python/.test(err)) + assert.ok(/not in PATH/.test(f.errorLog)) + } + }) - var f = new TestPythonFinder(null, done) - f.win = true + it('find python - no python, use python launcher', function () { + const f = new TestPythonFinder(null, done) + f.win = true - f.execFile = function (program, args, opts, cb) { - if (program === 'py.exe') { - t.notEqual(args.indexOf('-c'), -1) - return cb(null, 'Z:\\snake.exe') - } - if (/sys\.executable/.test(args[args.length - 1])) { - cb(new Error('not found')) - } else if (f.winDefaultLocations.includes(program)) { - cb(new Error('not found')) - } else if (/sys\.version_info/.test(args[args.length - 1])) { - if (program === 'Z:\\snake.exe') { - cb(null, '2.7.14') + f.execFile = function (program, args, opts, cb) { + if (program === 'py.exe') { + assert.notStrictEqual(args.indexOf('-3'), -1) + assert.notStrictEqual(args.indexOf('-c'), -1) + return cb(null, 'Z:\\snake.exe') + } + if (/sys\.executable/.test(args[args.length - 1])) { + cb(new Error('not found')) + } else if (f.winDefaultLocations.includes(program)) { + cb(new Error('not found')) + } else if (/sys\.version_info/.test(args[args.length - 1])) { + if (program === 'Z:\\snake.exe') { + cb(null, '3.9.0') + } else { + assert.fail() + } } else { - t.fail() + assert.fail() } - } else { - t.fail() } - } - f.findPython() - - function done (err, python) { - t.strictEqual(err, null) - t.strictEqual(python, 'Z:\\snake.exe') - } -}) + f.findPython() -test('find python - no python, no python launcher, good guess', function (t) { - t.plan(2) + function done (err, python) { + assert.strictEqual(err, null) + assert.strictEqual(python, 'Z:\\snake.exe') + } + }) - var re = /C:[\\/]Python37[\\/]python[.]exe/ - var f = new TestPythonFinder(null, done) - f.win = true + it('find python - no python, no python launcher, good guess', function () { + const f = new TestPythonFinder(null, done) + f.win = true + const expectedProgram = f.winDefaultLocations[0] - f.execFile = function (program, args, opts, cb) { - if (program === 'py.exe') { - return cb(new Error('not found')) - } - if (/sys\.executable/.test(args[args.length - 1])) { - cb(new Error('not found')) - } else if (re.test(program) && - /sys\.version_info/.test(args[args.length - 1])) { - cb(null, '3.7.3') - } else { - t.fail() + f.execFile = function (program, args, opts, cb) { + if (program === 'py.exe') { + return cb(new Error('not found')) + } + if (/sys\.executable/.test(args[args.length - 1])) { + cb(new Error('not found')) + } else if (program === expectedProgram && + /sys\.version_info/.test(args[args.length - 1])) { + cb(null, '3.7.3') + } else { + assert.fail() + } } - } - f.findPython() + f.findPython() - function done (err, python) { - t.strictEqual(err, null) - t.ok(re.test(python)) - } -}) - -test('find python - no python, no python launcher, bad guess', function (t) { - t.plan(2) + function done (err, python) { + assert.strictEqual(err, null) + assert.ok(python === expectedProgram) + } + }) - var f = new TestPythonFinder(null, done) - f.win = true + it('find python - no python, no python launcher, bad guess', function () { + const f = new TestPythonFinder(null, done) + f.win = true - f.execFile = function (program, args, opts, cb) { - if (/sys\.executable/.test(args[args.length - 1])) { - cb(new Error('not found')) - } else if (/sys\.version_info/.test(args[args.length - 1])) { - cb(new Error('not a Python executable')) - } else { - t.fail() + f.execFile = function (program, args, opts, cb) { + if (/sys\.executable/.test(args[args.length - 1])) { + cb(new Error('not found')) + } else if (/sys\.version_info/.test(args[args.length - 1])) { + cb(new Error('not a Python executable')) + } else { + assert.fail() + } } - } - f.findPython() + f.findPython() - function done (err) { - t.ok(/Could not find any Python/.test(err)) - t.ok(/not in PATH/.test(f.errorLog)) - } + function done (err) { + assert.ok(/Could not find any Python/.test(err)) + assert.ok(/not in PATH/.test(f.errorLog)) + } + }) }) diff --git a/test/test-find-visualstudio.js b/test/test-find-visualstudio.js index 1327cf8841..def1fc81f7 100644 --- a/test/test-find-visualstudio.js +++ b/test/test-find-visualstudio.js @@ -1,6 +1,7 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const fs = require('fs') const path = require('path') const findVisualStudio = require('../lib/find-visualstudio') @@ -15,7 +16,7 @@ function poison (object, property) { console.error(Error(`Property ${property} should not have been accessed.`)) process.abort() } - var descriptor = { + const descriptor = { configurable: false, enumerable: false, get: fail, @@ -26,651 +27,636 @@ function poison (object, property) { function TestVisualStudioFinder () { VisualStudioFinder.apply(this, arguments) } TestVisualStudioFinder.prototype = Object.create(VisualStudioFinder.prototype) -// Silence npmlog - remove for debugging -TestVisualStudioFinder.prototype.log = { - silly: () => {}, - verbose: () => {}, - info: () => {}, - warn: () => {}, - error: () => {} -} -test('VS2013', function (t) { - t.plan(4) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\MSBuild12\\MSBuild.exe', - path: 'C:\\VS2013', - sdk: null, - toolset: 'v120', - version: '12.0', - versionMajor: 12, - versionMinor: 0, - versionYear: 2013 +describe('find-visualstudio', function () { + it('VS2013', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\MSBuild12\\MSBuild.exe', + path: 'C:\\VS2013', + sdk: null, + toolset: 'v120', + version: '12.0', + versionMajor: 12, + versionMinor: 0, + versionYear: 2013 + }) }) - }) - finder.findVisualStudio2017OrNewer = (cb) => { - finder.parseData(new Error(), '', '', cb) - } - finder.regSearchKeys = (keys, value, addOpts, cb) => { - for (var i = 0; i < keys.length; ++i) { - const fullName = `${keys[i]}\\${value}` - switch (fullName) { - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - continue - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': - t.pass(`expected search for registry value ${fullName}`) - return cb(null, 'C:\\VS2013\\VC\\') - case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\12.0\\MSBuildToolsPath': - t.pass(`expected search for registry value ${fullName}`) - return cb(null, 'C:\\MSBuild12\\') - default: - t.fail(`unexpected search for registry value ${fullName}`) - } + finder.findVisualStudio2017OrNewer = (cb) => { + finder.parseData(new Error(), '', '', cb) } - return cb(new Error()) - } - finder.findVisualStudio() -}) - -test('VS2013 should not be found on new node versions', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder({ - major: 10, - minor: 0, - patch: 0 - }, null, (err, info) => { - t.ok(/find .* Visual Studio/i.test(err), 'expect error') - t.false(info, 'no data') - }) - - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.regSearchKeys = (keys, value, addOpts, cb) => { - for (var i = 0; i < keys.length; ++i) { - const fullName = `${keys[i]}\\${value}` - switch (fullName) { - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - continue - default: - t.fail(`unexpected search for registry value ${fullName}`) + finder.regSearchKeys = (keys, value, addOpts, cb) => { + for (let i = 0; i < keys.length; ++i) { + const fullName = `${keys[i]}\\${value}` + switch (fullName) { + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + continue + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': + assert.ok(true, `expected search for registry value ${fullName}`) + return cb(null, 'C:\\VS2013\\VC\\') + case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\12.0\\MSBuildToolsPath': + assert.ok(true, `expected search for registry value ${fullName}`) + return cb(null, 'C:\\MSBuild12\\') + default: + assert.fail(`unexpected search for registry value ${fullName}`) + } } + return cb(new Error()) } - return cb(new Error()) - } - finder.findVisualStudio() -}) + finder.findVisualStudio() + }) -test('VS2015', function (t) { - t.plan(4) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\MSBuild14\\MSBuild.exe', - path: 'C:\\VS2015', - sdk: null, - toolset: 'v140', - version: '14.0', - versionMajor: 14, - versionMinor: 0, - versionYear: 2015 + it('VS2013 should not be found on new node versions', function () { + const finder = new TestVisualStudioFinder({ + major: 10, + minor: 0, + patch: 0 + }, null, (err, info) => { + assert.ok(/find .* Visual Studio/i.test(err), 'expect error') + assert.ok(!info, 'no data') }) - }) - finder.findVisualStudio2017OrNewer = (cb) => { - finder.parseData(new Error(), '', '', cb) - } - finder.regSearchKeys = (keys, value, addOpts, cb) => { - for (var i = 0; i < keys.length; ++i) { - const fullName = `${keys[i]}\\${value}` - switch (fullName) { - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - t.pass(`expected search for registry value ${fullName}`) - return cb(null, 'C:\\VS2015\\VC\\') - case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\14.0\\MSBuildToolsPath': - t.pass(`expected search for registry value ${fullName}`) - return cb(null, 'C:\\MSBuild14\\') - default: - t.fail(`unexpected search for registry value ${fullName}`) + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.regSearchKeys = (keys, value, addOpts, cb) => { + for (let i = 0; i < keys.length; ++i) { + const fullName = `${keys[i]}\\${value}` + switch (fullName) { + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + continue + default: + assert.fail(`unexpected search for registry value ${fullName}`) + } } + return cb(new Error()) } - return cb(new Error()) - } - finder.findVisualStudio() -}) - -test('error from PowerShell', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, null) - - finder.parseData(new Error(), '', '', (info) => { - t.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') - t.false(info, 'no data') + finder.findVisualStudio() }) -}) -test('empty output from PowerShell', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, null) + it('VS2015', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\MSBuild14\\MSBuild.exe', + path: 'C:\\VS2015', + sdk: null, + toolset: 'v140', + version: '14.0', + versionMajor: 14, + versionMinor: 0, + versionYear: 2015 + }) + }) - finder.parseData(null, '', '', (info) => { - t.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') - t.false(info, 'no data') + finder.findVisualStudio2017OrNewer = (cb) => { + finder.parseData(new Error(), '', '', cb) + } + finder.regSearchKeys = (keys, value, addOpts, cb) => { + for (let i = 0; i < keys.length; ++i) { + const fullName = `${keys[i]}\\${value}` + switch (fullName) { + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + assert.ok(true, `expected search for registry value ${fullName}`) + return cb(null, 'C:\\VS2015\\VC\\') + case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\14.0\\MSBuildToolsPath': + assert.ok(true, `expected search for registry value ${fullName}`) + return cb(null, 'C:\\MSBuild14\\') + default: + assert.fail(`unexpected search for registry value ${fullName}`) + } + } + return cb(new Error()) + } + finder.findVisualStudio() }) -}) -test('output from PowerShell not JSON', function (t) { - t.plan(2) + it('error from PowerShell', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) - const finder = new TestVisualStudioFinder(semverV1, null, null) - - finder.parseData(null, 'AAAABBBB', '', (info) => { - t.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') - t.false(info, 'no data') + finder.parseData(new Error(), '', '', (info) => { + assert.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') + assert.ok(!info, 'no data') + }) }) -}) - -test('wrong JSON from PowerShell', function (t) { - t.plan(2) - const finder = new TestVisualStudioFinder(semverV1, null, null) + it('empty output from PowerShell', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) - finder.parseData(null, '{}', '', (info) => { - t.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') - t.false(info, 'no data') + finder.parseData(null, '', '', (info) => { + assert.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') + assert.ok(!info, 'no data') + }) }) -}) - -test('empty JSON from PowerShell', function (t) { - t.plan(2) - const finder = new TestVisualStudioFinder(semverV1, null, null) + it('output from PowerShell not JSON', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) - finder.parseData(null, '[]', '', (info) => { - t.ok(/find .* Visual Studio/i.test(finder.errorLog[0]), 'expect error') - t.false(info, 'no data') + finder.parseData(null, 'AAAABBBB', '', (info) => { + assert.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') + assert.ok(!info, 'no data') + }) }) -}) -test('future version', function (t) { - t.plan(3) + it('wrong JSON from PowerShell', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) - const finder = new TestVisualStudioFinder(semverV1, null, null) - - finder.parseData(null, JSON.stringify([{ - packages: [ - 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', - 'Microsoft.VisualStudio.Component.Windows10SDK.17763', - 'Microsoft.VisualStudio.VC.MSBuild.Base' - ], - path: 'C:\\VS', - version: '9999.9999.9999.9999' - }]), '', (info) => { - t.ok(/unknown version/i.test(finder.errorLog[0]), 'expect error') - t.ok(/find .* Visual Studio/i.test(finder.errorLog[1]), 'expect error') - t.false(info, 'no data') + finder.parseData(null, '{}', '', (info) => { + assert.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') + assert.ok(!info, 'no data') + }) }) -}) - -test('single unusable VS2017', function (t) { - t.plan(3) - const finder = new TestVisualStudioFinder(semverV1, null, null) + it('empty JSON from PowerShell', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) - const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', (info) => { - t.ok(/checking/i.test(finder.errorLog[0]), 'expect error') - t.ok(/find .* Visual Studio/i.test(finder.errorLog[2]), 'expect error') - t.false(info, 'no data') + finder.parseData(null, '[]', '', (info) => { + assert.ok(/find .* Visual Studio/i.test(finder.errorLog[0]), 'expect error') + assert.ok(!info, 'no data') + }) }) -}) -test('minimal VS2017 Build Tools', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + - 'BuildTools\\MSBuild\\15.0\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools', - sdk: '10.0.17134.0', - toolset: 'v141', - version: '15.9.28307.665', - versionMajor: 15, - versionMinor: 9, - versionYear: 2017 + it('future version', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) + + finder.parseData(null, JSON.stringify([{ + packages: [ + 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', + 'Microsoft.VisualStudio.Component.Windows10SDK.17763', + 'Microsoft.VisualStudio.VC.MSBuild.Base' + ], + path: 'C:\\VS', + version: '9999.9999.9999.9999' + }]), '', (info) => { + assert.ok(/unknown version/i.test(finder.errorLog[0]), 'expect error') + assert.ok(/find .* Visual Studio/i.test(finder.errorLog[1]), 'expect error') + assert.ok(!info, 'no data') }) }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', - 'VS_2017_BuildTools_minimal.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) + it('single unusable VS2017', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) -test('VS2017 Community with C++ workload', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + - 'Community\\MSBuild\\15.0\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community', - sdk: '10.0.17763.0', - toolset: 'v141', - version: '15.9.28307.665', - versionMajor: 15, - versionMinor: 9, - versionYear: 2017 + const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', (info) => { + assert.ok(/checking/i.test(finder.errorLog[0]), 'expect error') + assert.ok(/find .* Visual Studio/i.test(finder.errorLog[2]), 'expect error') + assert.ok(!info, 'no data') }) }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', - 'VS_2017_Community_workload.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) - -test('VS2017 Express', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + - 'WDExpress\\MSBuild\\15.0\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\WDExpress', - sdk: '10.0.17763.0', - toolset: 'v141', - version: '15.9.28307.858', - versionMajor: 15, - versionMinor: 9, - versionYear: 2017 + it('minimal VS2017 Build Tools', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + + 'BuildTools\\MSBuild\\15.0\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools', + sdk: '10.0.17134.0', + toolset: 'v141', + version: '15.9.28307.665', + versionMajor: 15, + versionMinor: 9, + versionYear: 2017 + }) }) - }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', 'VS_2017_Express.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2017_BuildTools_minimal.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() + }) -test('VS2019 Preview with C++ workload', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + - 'Preview\\MSBuild\\Current\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Preview', - sdk: '10.0.17763.0', - toolset: 'v142', - version: '16.0.28608.199', - versionMajor: 16, - versionMinor: 0, - versionYear: 2019 + it('VS2017 Community with C++ workload', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + + 'Community\\MSBuild\\15.0\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community', + sdk: '10.0.17763.0', + toolset: 'v141', + version: '15.9.28307.665', + versionMajor: 15, + versionMinor: 9, + versionYear: 2017 + }) }) - }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', - 'VS_2019_Preview.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2017_Community_workload.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() + }) -test('minimal VS2019 Build Tools', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + - 'BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools', - sdk: '10.0.17134.0', - toolset: 'v142', - version: '16.1.28922.388', - versionMajor: 16, - versionMinor: 1, - versionYear: 2019 + it('VS2017 Express', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + + 'WDExpress\\MSBuild\\15.0\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\WDExpress', + sdk: '10.0.17763.0', + toolset: 'v141', + version: '15.9.28307.858', + versionMajor: 15, + versionMinor: 9, + versionYear: 2017 + }) }) - }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', - 'VS_2019_BuildTools_minimal.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', 'VS_2017_Express.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() + }) -test('VS2019 Community with C++ workload', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + - 'Community\\MSBuild\\Current\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community', - sdk: '10.0.17763.0', - toolset: 'v142', - version: '16.1.28922.388', - versionMajor: 16, - versionMinor: 1, - versionYear: 2019 + it('VS2019 Preview with C++ workload', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + + 'Preview\\MSBuild\\Current\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Preview', + sdk: '10.0.17763.0', + toolset: 'v142', + version: '16.0.28608.199', + versionMajor: 16, + versionMinor: 0, + versionYear: 2019 + }) }) + + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2019_Preview.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', - 'VS_2019_Community_workload.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) + it('minimal VS2019 Build Tools', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + + 'BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools', + sdk: '10.0.17134.0', + toolset: 'v142', + version: '16.1.28922.388', + versionMajor: 16, + versionMinor: 1, + versionYear: 2019 + }) + }) -function allVsVersions (t, finder) { - finder.findVisualStudio2017OrNewer = (cb) => { - const data0 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2017_Unusable.txt'))) - const data1 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2017_BuildTools_minimal.txt'))) - const data2 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2017_Community_workload.txt'))) - const data3 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2017_Express.txt'))) - const data4 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2019_Preview.txt'))) - const data5 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2019_BuildTools_minimal.txt'))) - const data6 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2019_Community_workload.txt'))) - const data = JSON.stringify(data0.concat(data1, data2, data3, data4, - data5, data6)) - finder.parseData(null, data, '', cb) - } - finder.regSearchKeys = (keys, value, addOpts, cb) => { - for (var i = 0; i < keys.length; ++i) { - const fullName = `${keys[i]}\\${value}` - switch (fullName) { - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': - continue - case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': - return cb(null, 'C:\\VS2013\\VC\\') - case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\12.0\\MSBuildToolsPath': - return cb(null, 'C:\\MSBuild12\\') - case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - return cb(null, 'C:\\VS2015\\VC\\') - case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\14.0\\MSBuildToolsPath': - return cb(null, 'C:\\MSBuild14\\') - default: - t.fail(`unexpected search for registry value ${fullName}`) - } + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2019_BuildTools_minimal.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) } - return cb(new Error()) - } -} + finder.findVisualStudio() + }) -test('fail when looking for invalid path', function (t) { - t.plan(2) + it('VS2019 Community with C++ workload', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + + 'Community\\MSBuild\\Current\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community', + sdk: '10.0.17763.0', + toolset: 'v142', + version: '16.1.28922.388', + versionMajor: 16, + versionMinor: 1, + versionYear: 2019 + }) + }) - const finder = new TestVisualStudioFinder(semverV1, 'AABB', (err, info) => { - t.ok(/find .* Visual Studio/i.test(err), 'expect error') - t.false(info, 'no data') + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2019_Community_workload.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('look for VS2013 by version number', function (t) { - t.plan(2) + it('VS2022 Preview with C++ workload', function () { + const msBuildPath = process.arch === 'arm64' + ? 'C:\\Program Files\\Microsoft Visual Studio\\2022\\' + + 'Community\\MSBuild\\Current\\Bin\\arm64\\MSBuild.exe' + : 'C:\\Program Files\\Microsoft Visual Studio\\2022\\' + + 'Community\\MSBuild\\Current\\Bin\\MSBuild.exe' + + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: msBuildPath, + path: + 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community', + sdk: '10.0.22621.0', + toolset: 'v143', + version: '17.4.33213.308', + versionMajor: 17, + versionMinor: 4, + versionYear: 2022 + }) + }) - const finder = new TestVisualStudioFinder(semverV1, '2013', (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.versionYear, 2013) + poison(finder, 'regSearchKeys') + finder.msBuildPathExists = (path) => { + return true + } + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2022_Community_workload.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('look for VS2013 by installation path', function (t) { - t.plan(2) + function allVsVersions (finder) { + finder.findVisualStudio2017OrNewer = (cb) => { + const data0 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2017_Unusable.txt'))) + const data1 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2017_BuildTools_minimal.txt'))) + const data2 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2017_Community_workload.txt'))) + const data3 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2017_Express.txt'))) + const data4 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2019_Preview.txt'))) + const data5 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2019_BuildTools_minimal.txt'))) + const data6 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2019_Community_workload.txt'))) + const data7 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2022_Community_workload.txt'))) + const data = JSON.stringify(data0.concat(data1, data2, data3, data4, + data5, data6, data7)) + finder.parseData(null, data, '', cb) + } + finder.regSearchKeys = (keys, value, addOpts, cb) => { + for (let i = 0; i < keys.length; ++i) { + const fullName = `${keys[i]}\\${value}` + switch (fullName) { + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': + continue + case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': + return cb(null, 'C:\\VS2013\\VC\\') + case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\12.0\\MSBuildToolsPath': + return cb(null, 'C:\\MSBuild12\\') + case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + return cb(null, 'C:\\VS2015\\VC\\') + case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\14.0\\MSBuildToolsPath': + return cb(null, 'C:\\MSBuild14\\') + default: + assert.fail(`unexpected search for registry value ${fullName}`) + } + } + return cb(new Error()) + } + } - const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2013', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, 'C:\\VS2013') + it('fail when looking for invalid path', function () { + const finder = new TestVisualStudioFinder(semverV1, 'AABB', (err, info) => { + assert.ok(/find .* Visual Studio/i.test(err), 'expect error') + assert.ok(!info, 'no data') }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + allVsVersions(finder) + finder.findVisualStudio() + }) -test('look for VS2015 by version number', function (t) { - t.plan(2) + it('look for VS2013 by version number', function () { + const finder = new TestVisualStudioFinder(semverV1, '2013', (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2013) + }) - const finder = new TestVisualStudioFinder(semverV1, '2015', (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.versionYear, 2015) + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + it('look for VS2013 by installation path', function () { + const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2013', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, 'C:\\VS2013') + }) -test('look for VS2015 by installation path', function (t) { - t.plan(2) + allVsVersions(finder) + finder.findVisualStudio() + }) - const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, 'C:\\VS2015') + it('look for VS2015 by version number', function () { + const finder = new TestVisualStudioFinder(semverV1, '2015', (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2015) }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('look for VS2017 by version number', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, '2017', (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.versionYear, 2017) + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + it('look for VS2015 by installation path', function () { + const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, 'C:\\VS2015') + }) -test('look for VS2017 by installation path', function (t) { - t.plan(2) + allVsVersions(finder) + finder.findVisualStudio() + }) - const finder = new TestVisualStudioFinder(semverV1, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community') + it('look for VS2017 by version number', function () { + const finder = new TestVisualStudioFinder(semverV1, '2017', (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2017) }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('look for VS2019 by version number', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, '2019', (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.versionYear, 2019) + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('look for VS2019 by installation path', function (t) { - t.plan(2) + it('look for VS2017 by installation path', function () { + const finder = new TestVisualStudioFinder(semverV1, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community') + }) + + allVsVersions(finder) + finder.findVisualStudio() + }) - const finder = new TestVisualStudioFinder(semverV1, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + it('look for VS2019 by version number', function () { + const finder = new TestVisualStudioFinder(semverV1, '2019', (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2019) }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + allVsVersions(finder) + finder.findVisualStudio() + }) -test('msvs_version match should be case insensitive', function (t) { - t.plan(2) + it('look for VS2019 by installation path', function () { + const finder = new TestVisualStudioFinder(semverV1, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + }) + + allVsVersions(finder) + finder.findVisualStudio() + }) - const finder = new TestVisualStudioFinder(semverV1, - 'c:\\program files (x86)\\microsoft visual studio\\2019\\BUILDTOOLS', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + it('look for VS2022 by version number', function () { + const finder = new TestVisualStudioFinder(semverV1, '2022', (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2022) }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('latest version should be found by default', function (t) { - t.plan(2) + finder.msBuildPathExists = (path) => { + return true + } - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.versionYear, 2019) + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + it('msvs_version match should be case insensitive', function () { + const finder = new TestVisualStudioFinder(semverV1, + 'c:\\program files (x86)\\microsoft visual studio\\2019\\BUILDTOOLS', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + }) + + allVsVersions(finder) + finder.findVisualStudio() + }) -test('run on a usable VS Command Prompt', function (t) { - t.plan(2) + it('latest version should be found by default', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2022) + }) - process.env.VCINSTALLDIR = 'C:\\VS2015\\VC' - // VSINSTALLDIR is not defined on Visual C++ Build Tools 2015 - delete process.env.VSINSTALLDIR + finder.msBuildPathExists = (path) => { + return true + } - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, 'C:\\VS2015') + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + it('run on a usable VS Command Prompt', function () { + process.env.VCINSTALLDIR = 'C:\\VS2015\\VC' + // VSINSTALLDIR is not defined on Visual C++ Build Tools 2015 + delete process.env.VSINSTALLDIR -test('VCINSTALLDIR match should be case insensitive', function (t) { - t.plan(2) - - process.env.VCINSTALLDIR = - 'c:\\program files (x86)\\microsoft visual studio\\2019\\BUILDTOOLS\\VC' + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, 'C:\\VS2015') + }) - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('run on a unusable VS Command Prompt', function (t) { - t.plan(2) + it('VCINSTALLDIR match should be case insensitive', function () { + process.env.VCINSTALLDIR = + 'c:\\program files (x86)\\microsoft visual studio\\2019\\BUILDTOOLS\\VC' - process.env.VCINSTALLDIR = - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildToolsUnusable\\VC' + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + }) - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.ok(/find .* Visual Studio/i.test(err), 'expect error') - t.false(info, 'no data') + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + it('run on a unusable VS Command Prompt', function () { + process.env.VCINSTALLDIR = + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildToolsUnusable\\VC' -test('run on a VS Command Prompt with matching msvs_version', function (t) { - t.plan(2) + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.ok(/find .* Visual Studio/i.test(err), 'expect error') + assert.ok(!info, 'no data') + }) - process.env.VCINSTALLDIR = 'C:\\VS2015\\VC' + allVsVersions(finder) + finder.findVisualStudio() + }) - const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, 'C:\\VS2015') - }) + it('run on a VS Command Prompt with matching msvs_version', function () { + process.env.VCINSTALLDIR = 'C:\\VS2015\\VC' - allVsVersions(t, finder) - finder.findVisualStudio() -}) + const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, 'C:\\VS2015') + }) -test('run on a VS Command Prompt with mismatched msvs_version', function (t) { - t.plan(2) + allVsVersions(finder) + finder.findVisualStudio() + }) - process.env.VCINSTALLDIR = - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC' + it('run on a VS Command Prompt with mismatched msvs_version', function () { + process.env.VCINSTALLDIR = + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC' - const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', - (err, info) => { - t.ok(/find .* Visual Studio/i.test(err), 'expect error') - t.false(info, 'no data') - }) + const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', + (err, info) => { + assert.ok(/find .* Visual Studio/i.test(err), 'expect error') + assert.ok(!info, 'no data') + }) - allVsVersions(t, finder) - finder.findVisualStudio() + allVsVersions(finder) + finder.findVisualStudio() + }) }) diff --git a/test/test-install.js b/test/test-install.js index c3317155e0..af83ad9442 100644 --- a/test/test-install.js +++ b/test/test-install.js @@ -1,38 +1,131 @@ 'use strict' -const test = require('tap').test -const install = require('../lib/install').test.install +const { describe, it, after } = require('mocha') +const { rm } = require('fs/promises') +const assert = require('assert') +const path = require('path') +const os = require('os') +const util = require('util') +const { test: { download, install } } = require('../lib/install') +const gyp = require('../lib/node-gyp') +const semver = require('semver') +const stream = require('stream') +const streamPipeline = util.promisify(stream.pipeline) -require('npmlog').level = 'error' // we expect a warning +describe('install', function () { + it('EACCES retry once', async () => { + const fs = { + promises: { + stat (_) { + const err = new Error() + err.code = 'EACCES' + assert.ok(true) + throw err + } + } + } -test('EACCES retry once', function (t) { - t.plan(3) + const Gyp = { + devDir: __dirname, + opts: { + ensure: true + }, + commands: { + install (argv, cb) { + install(fs, Gyp, argv).then(cb, cb) + }, + remove (_, cb) { + cb() + } + } + } - var fs = {} - fs.stat = function (path, cb) { - var err = new Error() - err.code = 'EACCES' - cb(err) - t.ok(true) - } + try { + await install(fs, Gyp, []) + } catch (err) { + assert.ok(true) + if (/"pre" versions of node cannot be installed/.test(err.message)) { + assert.ok(true) + } + } + }) - var gyp = {} - gyp.devDir = __dirname - gyp.opts = {} - gyp.opts.ensure = true - gyp.commands = {} - gyp.commands.install = function (argv, cb) { - install(fs, gyp, argv, cb) - } - gyp.commands.remove = function (argv, cb) { - cb() - } + // only run these tests if we are running a version of Node with predictable version path behavior + const skipParallelInstallTests = process.env.FAST_TEST || + process.release.name !== 'node' || + semver.prerelease(process.version) !== null || + semver.satisfies(process.version, '<10') - gyp.commands.install([], function (err) { - t.ok(true) - if (/"pre" versions of node cannot be installed/.test(err.message)) { - t.ok(true) - t.ok(true) + async function parallelInstallsTest (test, fs, devDir, prog) { + if (skipParallelInstallTests) { + return test.skip('Skipping parallel installs test due to test environment configuration') } + + after(async () => { + await rm(devDir, { recursive: true, force: true }) + }) + + const expectedDir = path.join(devDir, process.version.replace(/^v/, '')) + await rm(expectedDir, { recursive: true, force: true }) + + await Promise.all([ + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []) + ]) + } + + it('parallel installs (ensure=true)', async function () { + this.timeout(600000) + + const fs = require('graceful-fs') + const devDir = await util.promisify(fs.mkdtemp)(path.join(os.tmpdir(), 'node-gyp-test-')) + + const prog = gyp() + prog.parseArgv([]) + prog.devDir = devDir + prog.opts.ensure = true + + await parallelInstallsTest(this, fs, devDir, prog) + }) + + it('parallel installs (ensure=false)', async function () { + this.timeout(600000) + + const fs = require('graceful-fs') + const devDir = await util.promisify(fs.mkdtemp)(path.join(os.tmpdir(), 'node-gyp-test-')) + + const prog = gyp() + prog.parseArgv([]) + prog.devDir = devDir + prog.opts.ensure = false + + await parallelInstallsTest(this, fs, devDir, prog) + }) + + it('parallel installs (tarball)', async function () { + this.timeout(600000) + + const fs = require('graceful-fs') + const devDir = await util.promisify(fs.mkdtemp)(path.join(os.tmpdir(), 'node-gyp-test-')) + + const prog = gyp() + prog.parseArgv([]) + prog.devDir = devDir + prog.opts.tarball = path.join(devDir, 'node-headers.tar.gz') + + await streamPipeline( + (await download(prog, `https://nodejs.org/dist/${process.version}/node-${process.version}.tar.gz`)).body, + fs.createWriteStream(prog.opts.tarball) + ) + + await parallelInstallsTest(this, fs, devDir, prog) }) }) diff --git a/test/test-options.js b/test/test-options.js index b2ac62c874..8d281db8e8 100644 --- a/test/test-options.js +++ b/test/test-options.js @@ -1,31 +1,50 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const gyp = require('../lib/node-gyp') -test('options in environment', (t) => { - t.plan(1) +describe('options', function () { + it('options in environment', () => { + // `npm test` dumps a ton of npm_config_* variables in the environment. + Object.keys(process.env) + .filter((key) => /^npm_config_/.test(key)) + .forEach((key) => { delete process.env[key] }) - // `npm test` dumps a ton of npm_config_* variables in the environment. - Object.keys(process.env) - .filter((key) => /^npm_config_/.test(key)) - .forEach((key) => { delete process.env[key] }) + // in some platforms, certain keys are stubborn and cannot be removed + const keys = Object.keys(process.env) + .filter((key) => /^npm_config_/.test(key)) + .map((key) => key.substring('npm_config_'.length)) + .concat('argv', 'x') - // in some platforms, certain keys are stubborn and cannot be removed - const keys = Object.keys(process.env) - .filter((key) => /^npm_config_/.test(key)) - .map((key) => key.substring('npm_config_'.length)) - .concat('argv', 'x') + // Zero-length keys should get filtered out. + process.env.npm_config_ = '42' + // Other keys should get added. + process.env.npm_config_x = '42' + // Except loglevel. + process.env.npm_config_loglevel = 'debug' - // Zero-length keys should get filtered out. - process.env.npm_config_ = '42' - // Other keys should get added. - process.env.npm_config_x = '42' - // Except loglevel. - process.env.npm_config_loglevel = 'debug' + const g = gyp() + g.parseArgv(['rebuild']) // Also sets opts.argv. - const g = gyp() - g.parseArgv(['rebuild']) // Also sets opts.argv. + assert.deepStrictEqual(Object.keys(g.opts).sort(), keys.sort()) + }) - t.deepEqual(Object.keys(g.opts).sort(), keys.sort()) + it('options with spaces in environment', () => { + process.env.npm_config_force_process_config = 'true' + + const g = gyp() + g.parseArgv(['rebuild']) // Also sets opts.argv. + + assert.strictEqual(g.opts['force-process-config'], 'true') + }) + + it('options with msvs_version', () => { + process.env.npm_config_msvs_version = '2017' + + const g = gyp() + g.parseArgv(['rebuild']) // Also sets opts.argv. + + assert.strictEqual(g.opts['msvs-version'], '2017') + }) }) diff --git a/test/test-process-release.js b/test/test-process-release.js index c3ee0703c5..31a87be9e9 100644 --- a/test/test-process-release.js +++ b/test/test-process-release.js @@ -1,434 +1,401 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const processRelease = require('../lib/process-release') -test('test process release - process.version = 0.8.20', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.8.20', null) - - t.equal(release.semver.version, '0.8.20') - delete release.semver - - t.deepEqual(release, { - version: '0.8.20', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.8.20/', - tarballUrl: 'https://nodejs.org/dist/v0.8.20/node-v0.8.20.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.8.20/SHASUMS256.txt', - versionDir: '0.8.20', - ia32: { libUrl: 'https://nodejs.org/dist/v0.8.20/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.8.20/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.8.20/arm64/node.lib', libPath: 'arm64/node.lib' } +describe('process-release', function () { + it('test process release - process.version = 0.8.20', function () { + const release = processRelease([], { opts: {} }, 'v0.8.20', null) + + assert.strictEqual(release.semver.version, '0.8.20') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.8.20', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.8.20/', + tarballUrl: 'https://nodejs.org/dist/v0.8.20/node-v0.8.20.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.8.20/SHASUMS256.txt', + versionDir: '0.8.20', + ia32: { libUrl: 'https://nodejs.org/dist/v0.8.20/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.8.20/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.8.20/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -test('test process release - process.version = 0.10.21', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.10.21', null) - - t.equal(release.semver.version, '0.10.21') - delete release.semver - - t.deepEqual(release, { - version: '0.10.21', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.10.21/', - tarballUrl: 'https://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.10.21/SHASUMS256.txt', - versionDir: '0.10.21', - ia32: { libUrl: 'https://nodejs.org/dist/v0.10.21/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.10.21/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.10.21/arm64/node.lib', libPath: 'arm64/node.lib' } + it('test process release - process.version = 0.10.21', function () { + const release = processRelease([], { opts: {} }, 'v0.10.21', null) + + assert.strictEqual(release.semver.version, '0.10.21') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.10.21', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.10.21/', + tarballUrl: 'https://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.10.21/SHASUMS256.txt', + versionDir: '0.10.21', + ia32: { libUrl: 'https://nodejs.org/dist/v0.10.21/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.10.21/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.10.21/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -// prior to -headers.tar.gz -test('test process release - process.version = 0.12.9', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.12.9', null) - - t.equal(release.semver.version, '0.12.9') - delete release.semver - - t.deepEqual(release, { - version: '0.12.9', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.12.9/', - tarballUrl: 'https://nodejs.org/dist/v0.12.9/node-v0.12.9.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.12.9/SHASUMS256.txt', - versionDir: '0.12.9', - ia32: { libUrl: 'https://nodejs.org/dist/v0.12.9/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.12.9/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.12.9/arm64/node.lib', libPath: 'arm64/node.lib' } + // prior to -headers.tar.gz + it('test process release - process.version = 0.12.9', function () { + const release = processRelease([], { opts: {} }, 'v0.12.9', null) + + assert.strictEqual(release.semver.version, '0.12.9') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.12.9', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.12.9/', + tarballUrl: 'https://nodejs.org/dist/v0.12.9/node-v0.12.9.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.12.9/SHASUMS256.txt', + versionDir: '0.12.9', + ia32: { libUrl: 'https://nodejs.org/dist/v0.12.9/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.12.9/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.12.9/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -// prior to -headers.tar.gz -test('test process release - process.version = 0.10.41', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.10.41', null) - - t.equal(release.semver.version, '0.10.41') - delete release.semver - - t.deepEqual(release, { - version: '0.10.41', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.10.41/', - tarballUrl: 'https://nodejs.org/dist/v0.10.41/node-v0.10.41.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.10.41/SHASUMS256.txt', - versionDir: '0.10.41', - ia32: { libUrl: 'https://nodejs.org/dist/v0.10.41/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.10.41/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.10.41/arm64/node.lib', libPath: 'arm64/node.lib' } + // prior to -headers.tar.gz + it('test process release - process.version = 0.10.41', function () { + const release = processRelease([], { opts: {} }, 'v0.10.41', null) + + assert.strictEqual(release.semver.version, '0.10.41') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.10.41', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.10.41/', + tarballUrl: 'https://nodejs.org/dist/v0.10.41/node-v0.10.41.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.10.41/SHASUMS256.txt', + versionDir: '0.10.41', + ia32: { libUrl: 'https://nodejs.org/dist/v0.10.41/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.10.41/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.10.41/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -// has -headers.tar.gz -test('test process release - process.release ~ node@0.10.42', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.10.42', null) - - t.equal(release.semver.version, '0.10.42') - delete release.semver - - t.deepEqual(release, { - version: '0.10.42', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.10.42/', - tarballUrl: 'https://nodejs.org/dist/v0.10.42/node-v0.10.42-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.10.42/SHASUMS256.txt', - versionDir: '0.10.42', - ia32: { libUrl: 'https://nodejs.org/dist/v0.10.42/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.10.42/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.10.42/arm64/node.lib', libPath: 'arm64/node.lib' } + // has -headers.tar.gz + it('test process release - process.release ~ node@0.10.42', function () { + const release = processRelease([], { opts: {} }, 'v0.10.42', null) + + assert.strictEqual(release.semver.version, '0.10.42') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.10.42', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.10.42/', + tarballUrl: 'https://nodejs.org/dist/v0.10.42/node-v0.10.42-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.10.42/SHASUMS256.txt', + versionDir: '0.10.42', + ia32: { libUrl: 'https://nodejs.org/dist/v0.10.42/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.10.42/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.10.42/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -// has -headers.tar.gz -test('test process release - process.release ~ node@0.12.10', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.12.10', null) - - t.equal(release.semver.version, '0.12.10') - delete release.semver - - t.deepEqual(release, { - version: '0.12.10', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.12.10/', - tarballUrl: 'https://nodejs.org/dist/v0.12.10/node-v0.12.10-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.12.10/SHASUMS256.txt', - versionDir: '0.12.10', - ia32: { libUrl: 'https://nodejs.org/dist/v0.12.10/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.12.10/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.12.10/arm64/node.lib', libPath: 'arm64/node.lib' } + // has -headers.tar.gz + it('test process release - process.release ~ node@0.12.10', function () { + const release = processRelease([], { opts: {} }, 'v0.12.10', null) + + assert.strictEqual(release.semver.version, '0.12.10') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.12.10', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.12.10/', + tarballUrl: 'https://nodejs.org/dist/v0.12.10/node-v0.12.10-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.12.10/SHASUMS256.txt', + versionDir: '0.12.10', + ia32: { libUrl: 'https://nodejs.org/dist/v0.12.10/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.12.10/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.12.10/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -test('test process release - process.release ~ node@4.1.23', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v4.1.23', { - name: 'node', - headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + it('test process release - process.release ~ node@4.1.23', function () { + const release = processRelease([], { opts: {} }, 'v4.1.23', { + name: 'node', + headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v4.1.23/', + tarballUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v4.1.23/SHASUMS256.txt', + versionDir: '4.1.23', + ia32: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v4.1.23/', - tarballUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v4.1.23/SHASUMS256.txt', - versionDir: '4.1.23', - ia32: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + it('test process release - process.release ~ node@4.1.23 / corp build', function () { + const release = processRelease([], { opts: {} }, 'v4.1.23', { + name: 'node', + headersUrl: 'https://some.custom.location/node-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'node', + baseUrl: 'https://some.custom.location/', + tarballUrl: 'https://some.custom.location/node-v4.1.23-headers.tar.gz', + shasumsUrl: 'https://some.custom.location/SHASUMS256.txt', + versionDir: '4.1.23', + ia32: { libUrl: 'https://some.custom.location/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://some.custom.location/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://some.custom.location/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) -}) -test('test process release - process.release ~ node@4.1.23 / corp build', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v4.1.23', { - name: 'node', - headersUrl: 'https://some.custom.location/node-v4.1.23-headers.tar.gz' + it('test process release - process.release ~ node@12.8.0 Windows', function () { + const release = processRelease([], { opts: {} }, 'v12.8.0', { + name: 'node', + sourceUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0.tar.gz', + headersUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', + libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x64/node.lib' + }) + + assert.strictEqual(release.semver.version, '12.8.0') + delete release.semver + + assert.deepStrictEqual(release, { + version: '12.8.0', + name: 'node', + baseUrl: 'https://nodejs.org/download/release/v12.8.0/', + tarballUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/download/release/v12.8.0/SHASUMS256.txt', + versionDir: '12.8.0', + ia32: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'node', - baseUrl: 'https://some.custom.location/', - tarballUrl: 'https://some.custom.location/node-v4.1.23-headers.tar.gz', - shasumsUrl: 'https://some.custom.location/SHASUMS256.txt', - versionDir: '4.1.23', - ia32: { libUrl: 'https://some.custom.location/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://some.custom.location/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://some.custom.location/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + it('test process release - process.release ~ node@12.8.0 Windows ARM64', function () { + const release = processRelease([], { opts: {} }, 'v12.8.0', { + name: 'node', + sourceUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0.tar.gz', + headersUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', + libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-arm64/node.lib' + }) + + assert.strictEqual(release.semver.version, '12.8.0') + delete release.semver + + assert.deepStrictEqual(release, { + version: '12.8.0', + name: 'node', + baseUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/', + tarballUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', + shasumsUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/SHASUMS256.txt', + versionDir: '12.8.0', + ia32: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) -}) -test('test process release - process.release ~ node@12.8.0 Windows', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v12.8.0', { - name: 'node', - sourceUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0.tar.gz', - headersUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', - libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x64/node.lib' - }) - - t.equal(release.semver.version, '12.8.0') - delete release.semver - - t.deepEqual(release, { - version: '12.8.0', - name: 'node', - baseUrl: 'https://nodejs.org/download/release/v12.8.0/', - tarballUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/download/release/v12.8.0/SHASUMS256.txt', - versionDir: '12.8.0', - ia32: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + it('test process release - process.release ~ node@4.1.23 --target=0.10.40', function () { + const release = processRelease([], { opts: { target: '0.10.40' } }, 'v4.1.23', { + name: 'node', + headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '0.10.40') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.10.40', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.10.40/', + tarballUrl: 'https://nodejs.org/dist/v0.10.40/node-v0.10.40.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.10.40/SHASUMS256.txt', + versionDir: '0.10.40', + ia32: { libUrl: 'https://nodejs.org/dist/v0.10.40/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.10.40/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.10.40/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -test('test process release - process.release ~ node@12.8.0 Windows ARM64', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v12.8.0', { - name: 'node', - sourceUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0.tar.gz', - headersUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', - libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-arm64/node.lib' + it('test process release - process.release ~ node@4.1.23 --dist-url=https://foo.bar/baz', function () { + const release = processRelease([], { opts: { 'dist-url': 'https://foo.bar/baz' } }, 'v4.1.23', { + name: 'node', + headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'node', + baseUrl: 'https://foo.bar/baz/v4.1.23/', + tarballUrl: 'https://foo.bar/baz/v4.1.23/node-v4.1.23-headers.tar.gz', + shasumsUrl: 'https://foo.bar/baz/v4.1.23/SHASUMS256.txt', + versionDir: '4.1.23', + ia32: { libUrl: 'https://foo.bar/baz/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://foo.bar/baz/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://foo.bar/baz/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) - t.equal(release.semver.version, '12.8.0') - delete release.semver - - t.deepEqual(release, { - version: '12.8.0', - name: 'node', - baseUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/', - tarballUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', - shasumsUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/SHASUMS256.txt', - versionDir: '12.8.0', - ia32: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + it('test process release - process.release ~ frankenstein@4.1.23', function () { + const release = processRelease([], { opts: {} }, 'v4.1.23', { + name: 'frankenstein', + headersUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'frankenstein', + baseUrl: 'https://frankensteinjs.org/dist/v4.1.23/', + tarballUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23-headers.tar.gz', + shasumsUrl: 'https://frankensteinjs.org/dist/v4.1.23/SHASUMS256.txt', + versionDir: 'frankenstein-4.1.23', + ia32: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-x86/frankenstein.lib', libPath: 'win-x86/frankenstein.lib' }, + x64: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-x64/frankenstein.lib', libPath: 'win-x64/frankenstein.lib' }, + arm64: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-arm64/frankenstein.lib', libPath: 'win-arm64/frankenstein.lib' } + }) }) -}) -test('test process release - process.release ~ node@4.1.23 --target=0.10.40', function (t) { - t.plan(2) - - var release = processRelease([], { opts: { target: '0.10.40' } }, 'v4.1.23', { - name: 'node', - headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + it('test process release - process.release ~ frankenstein@4.1.23 --dist-url=http://foo.bar/baz/', function () { + const release = processRelease([], { opts: { 'dist-url': 'http://foo.bar/baz/' } }, 'v4.1.23', { + name: 'frankenstein', + headersUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'frankenstein', + baseUrl: 'http://foo.bar/baz/v4.1.23/', + tarballUrl: 'http://foo.bar/baz/v4.1.23/frankenstein-v4.1.23-headers.tar.gz', + shasumsUrl: 'http://foo.bar/baz/v4.1.23/SHASUMS256.txt', + versionDir: 'frankenstein-4.1.23', + ia32: { libUrl: 'http://foo.bar/baz/v4.1.23/win-x86/frankenstein.lib', libPath: 'win-x86/frankenstein.lib' }, + x64: { libUrl: 'http://foo.bar/baz/v4.1.23/win-x64/frankenstein.lib', libPath: 'win-x64/frankenstein.lib' }, + arm64: { libUrl: 'http://foo.bar/baz/v4.1.23/win-arm64/frankenstein.lib', libPath: 'win-arm64/frankenstein.lib' } + }) }) - t.equal(release.semver.version, '0.10.40') - delete release.semver - - t.deepEqual(release, { - version: '0.10.40', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.10.40/', - tarballUrl: 'https://nodejs.org/dist/v0.10.40/node-v0.10.40.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.10.40/SHASUMS256.txt', - versionDir: '0.10.40', - ia32: { libUrl: 'https://nodejs.org/dist/v0.10.40/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.10.40/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.10.40/arm64/node.lib', libPath: 'arm64/node.lib' } + it('test process release - process.release ~ node@4.0.0-rc.4', function () { + const release = processRelease([], { opts: {} }, 'v4.0.0-rc.4', { + name: 'node', + headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.0.0-rc.4') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.0.0-rc.4', + name: 'node', + baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', + tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', + versionDir: '4.0.0-rc.4', + ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) -}) - -test('test process release - process.release ~ node@4.1.23 --dist-url=https://foo.bar/baz', function (t) { - t.plan(2) - - var release = processRelease([], { opts: { 'dist-url': 'https://foo.bar/baz' } }, 'v4.1.23', { - name: 'node', - headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' - }) - - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'node', - baseUrl: 'https://foo.bar/baz/v4.1.23/', - tarballUrl: 'https://foo.bar/baz/v4.1.23/node-v4.1.23-headers.tar.gz', - shasumsUrl: 'https://foo.bar/baz/v4.1.23/SHASUMS256.txt', - versionDir: '4.1.23', - ia32: { libUrl: 'https://foo.bar/baz/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://foo.bar/baz/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://foo.bar/baz/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } - }) -}) - -test('test process release - process.release ~ frankenstein@4.1.23', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v4.1.23', { - name: 'frankenstein', - headersUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23-headers.tar.gz' - }) - - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'frankenstein', - baseUrl: 'https://frankensteinjs.org/dist/v4.1.23/', - tarballUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23-headers.tar.gz', - shasumsUrl: 'https://frankensteinjs.org/dist/v4.1.23/SHASUMS256.txt', - versionDir: 'frankenstein-4.1.23', - ia32: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-x86/frankenstein.lib', libPath: 'win-x86/frankenstein.lib' }, - x64: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-x64/frankenstein.lib', libPath: 'win-x64/frankenstein.lib' }, - arm64: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-arm64/frankenstein.lib', libPath: 'win-arm64/frankenstein.lib' } - }) -}) - -test('test process release - process.release ~ frankenstein@4.1.23 --dist-url=http://foo.bar/baz/', function (t) { - t.plan(2) - - var release = processRelease([], { opts: { 'dist-url': 'http://foo.bar/baz/' } }, 'v4.1.23', { - name: 'frankenstein', - headersUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23.tar.gz' - }) - - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'frankenstein', - baseUrl: 'http://foo.bar/baz/v4.1.23/', - tarballUrl: 'http://foo.bar/baz/v4.1.23/frankenstein-v4.1.23-headers.tar.gz', - shasumsUrl: 'http://foo.bar/baz/v4.1.23/SHASUMS256.txt', - versionDir: 'frankenstein-4.1.23', - ia32: { libUrl: 'http://foo.bar/baz/v4.1.23/win-x86/frankenstein.lib', libPath: 'win-x86/frankenstein.lib' }, - x64: { libUrl: 'http://foo.bar/baz/v4.1.23/win-x64/frankenstein.lib', libPath: 'win-x64/frankenstein.lib' }, - arm64: { libUrl: 'http://foo.bar/baz/v4.1.23/win-arm64/frankenstein.lib', libPath: 'win-arm64/frankenstein.lib' } - }) -}) - -test('test process release - process.release ~ node@4.0.0-rc.4', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v4.0.0-rc.4', { - name: 'node', - headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' - }) - - t.equal(release.semver.version, '4.0.0-rc.4') - delete release.semver - - t.deepEqual(release, { - version: '4.0.0-rc.4', - name: 'node', - baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', - tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', - versionDir: '4.0.0-rc.4', - ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } - }) -}) - -test('test process release - process.release ~ node@4.0.0-rc.4 passed as argv[0]', function (t) { - t.plan(2) + it('test process release - process.release ~ node@4.0.0-rc.4 passed as argv[0]', function () { // note the missing 'v' on the arg, it should normalise when checking - // whether we're on the default or not - var release = processRelease(['4.0.0-rc.4'], { opts: {} }, 'v4.0.0-rc.4', { - name: 'node', - headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' - }) - - t.equal(release.semver.version, '4.0.0-rc.4') - delete release.semver - - t.deepEqual(release, { - version: '4.0.0-rc.4', - name: 'node', - baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', - tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', - versionDir: '4.0.0-rc.4', - ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + // whether we're on the default or not + const release = processRelease(['4.0.0-rc.4'], { opts: {} }, 'v4.0.0-rc.4', { + name: 'node', + headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.0.0-rc.4') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.0.0-rc.4', + name: 'node', + baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', + tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', + versionDir: '4.0.0-rc.4', + ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) -}) - -test('test process release - process.release ~ node@4.0.0-rc.4 - bogus string passed as argv[0]', function (t) { - t.plan(2) + it('test process release - process.release ~ node@4.0.0-rc.4 - bogus string passed as argv[0]', function () { // additional arguments can be passed in on the commandline that should be ignored if they - // are not specifying a valid version @ position 0 - var release = processRelease(['this is no version!'], { opts: {} }, 'v4.0.0-rc.4', { - name: 'node', - headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' + // are not specifying a valid version @ position 0 + const release = processRelease(['this is no version!'], { opts: {} }, 'v4.0.0-rc.4', { + name: 'node', + headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.0.0-rc.4') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.0.0-rc.4', + name: 'node', + baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', + tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', + versionDir: '4.0.0-rc.4', + ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) - t.equal(release.semver.version, '4.0.0-rc.4') - delete release.semver - - t.deepEqual(release, { - version: '4.0.0-rc.4', - name: 'node', - baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', - tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', - versionDir: '4.0.0-rc.4', - ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + it('test process release - NODEJS_ORG_MIRROR', function () { + process.env.NODEJS_ORG_MIRROR = 'http://foo.bar' + + const release = processRelease([], { opts: {} }, 'v4.1.23', { + name: 'node', + headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'node', + baseUrl: 'http://foo.bar/v4.1.23/', + tarballUrl: 'http://foo.bar/v4.1.23/node-v4.1.23-headers.tar.gz', + shasumsUrl: 'http://foo.bar/v4.1.23/SHASUMS256.txt', + versionDir: '4.1.23', + ia32: { libUrl: 'http://foo.bar/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'http://foo.bar/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'http://foo.bar/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) + + delete process.env.NODEJS_ORG_MIRROR }) }) - -test('test process release - NODEJS_ORG_MIRROR', function (t) { - t.plan(2) - - process.env.NODEJS_ORG_MIRROR = 'http://foo.bar' - - var release = processRelease([], { opts: {} }, 'v4.1.23', { - name: 'node', - headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' - }) - - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'node', - baseUrl: 'http://foo.bar/v4.1.23/', - tarballUrl: 'http://foo.bar/v4.1.23/node-v4.1.23-headers.tar.gz', - shasumsUrl: 'http://foo.bar/v4.1.23/SHASUMS256.txt', - versionDir: '4.1.23', - ia32: { libUrl: 'http://foo.bar/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'http://foo.bar/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'http://foo.bar/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } - }) - - delete process.env.NODEJS_ORG_MIRROR -}) diff --git a/update-gyp.py b/update-gyp.py index aa2bcb9eb9..70e2d10028 100755 --- a/update-gyp.py +++ b/update-gyp.py @@ -4,14 +4,13 @@ import os import shutil import subprocess -import sys import tarfile import tempfile import urllib.request BASE_URL = "https://github.com/nodejs/gyp-next/archive/" CHECKOUT_PATH = os.path.dirname(os.path.realpath(__file__)) -CHECKOUT_GYP_PATH = os.path.join(CHECKOUT_PATH, 'gyp') +CHECKOUT_GYP_PATH = os.path.join(CHECKOUT_PATH, "gyp") parser = argparse.ArgumentParser() parser.add_argument("tag", help="gyp tag to update to") @@ -21,25 +20,45 @@ changed_files = subprocess.check_output(["git", "diff", "--name-only"]).strip() if changed_files: - raise Exception("Can't update gyp while you have uncommitted changes in node-gyp") + raise Exception("Can't update gyp while you have uncommitted changes in node-gyp") with tempfile.TemporaryDirectory() as tmp_dir: - tar_file = os.path.join(tmp_dir, 'gyp.tar.gz') - unzip_target = os.path.join(tmp_dir, 'gyp') - with open(tar_file, 'wb') as f: - print("Downloading gyp-next@" + args.tag + " into temporary directory...") - print("From: " + tar_url) - with urllib.request.urlopen(tar_url) as in_file: - f.write(in_file.read()) - - print("Unzipping...") - with tarfile.open(tar_file, "r:gz") as tar_ref: - tar_ref.extractall(unzip_target) - - print("Moving to current checkout (" + CHECKOUT_PATH + ")...") - if os.path.exists(CHECKOUT_GYP_PATH): - shutil.rmtree(CHECKOUT_GYP_PATH) - shutil.move(os.path.join(unzip_target, os.listdir(unzip_target)[0]), CHECKOUT_GYP_PATH) + tar_file = os.path.join(tmp_dir, "gyp.tar.gz") + unzip_target = os.path.join(tmp_dir, "gyp") + with open(tar_file, "wb") as f: + print("Downloading gyp-next@" + args.tag + " into temporary directory...") + print("From: " + tar_url) + with urllib.request.urlopen(tar_url) as in_file: + f.write(in_file.read()) + + print("Unzipping...") + with tarfile.open(tar_file, "r:gz") as tar_ref: + def is_within_directory(directory, target): + + abs_directory = os.path.abspath(directory) + abs_target = os.path.abspath(target) + + prefix = os.path.commonprefix([abs_directory, abs_target]) + + return prefix == abs_directory + + def safe_extract(tar, path=".", members=None, *, numeric_owner=False): + + for member in tar.getmembers(): + member_path = os.path.join(path, member.name) + if not is_within_directory(path, member_path): + raise Exception("Attempted Path Traversal in Tar File") + + tar.extractall(path, members, numeric_owner=numeric_owner) + + safe_extract(tar_ref, unzip_target) + + print("Moving to current checkout (" + CHECKOUT_PATH + ")...") + if os.path.exists(CHECKOUT_GYP_PATH): + shutil.rmtree(CHECKOUT_GYP_PATH) + shutil.move( + os.path.join(unzip_target, os.listdir(unzip_target)[0]), CHECKOUT_GYP_PATH + ) subprocess.check_output(["git", "add", "gyp"], cwd=CHECKOUT_PATH) -subprocess.check_output(["git", "commit", "-m", "gyp: update gyp to " + args.tag]) +subprocess.check_output(["git", "commit", "-m", "feat(gyp): update gyp to " + args.tag])