diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index ca36b5a..ad54448 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -9,6 +9,9 @@ on: - '**' workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: lint: @@ -19,9 +22,9 @@ jobs: node-version: [lts/*] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Install Dependencies @@ -31,112 +34,151 @@ jobs: - name: Inspect Lockfile run: npm run lint:lockfile - linux: - runs-on: ubuntu-latest - + test_x86_x64: strategy: matrix: - node-version: [16.x, 18.x, 20.x] - + os: [ ubuntu-latest, windows-latest ] + node: [ 16, 18, 20 ] + arch: [ x86, x64 ] + exclude: + # Ubuntu does not ship x86 builds. + - { os: ubuntu-latest, arch: x86 } + runs-on: ${{ matrix.os }} + name: ${{ matrix.os }} / Node ${{ matrix.node }} ${{ matrix.arch }} steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - name: Install Dependencies - run: npm ci - - name: Rebuild - run: npm run rebuild - - name: Run Unit - run: npm run unit - - name: Post Unit Test Coverage - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: ./coverage/unit/ - files: lcov.info - flags: unit-tests-${{ matrix.node-version }}-linux - - name: Run Integration - run: npm run integration - - name: Post Integration Test Coverage - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: ./coverage/integration/ - files: lcov.info - flags: integration-tests-${{ matrix.node-version }}-linux + - name: Checkout + uses: actions/checkout@v4 + - name: Use node ${{ matrix.node }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + architecture: ${{ matrix.arch }} + - uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/node_modules + key: ${{ matrix.os }}-${{ matrix.arch }}-node-${{ matrix.node }}-${{ hashFiles('./package.json') }} + - name: Install + run: npm install + - name: Unit Test + run: npm run unit + - name: Post Unit Test Coverage + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + directory: ./coverage/unit/ + files: lcov.info + flags: unit-tests-${{ matrix.node }}-${{ matrix.os }}-${{ matrix.arch }} + - name: Integration Test + run: npm run integration + - name: Post Integration Test Coverage + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + directory: ./coverage/integration/ + files: lcov.info + flags: integration-tests-${{ matrix.node }}-${{ matrix.os }}-${{ matrix.arch }} - windows-2019: - runs-on: windows-2019 + test_macos_arm: strategy: matrix: - node-version: [16.x, 18.x, 20.x] - + os: [ macos-14 ] + node: [ 16, 18, 20 ] + arch: [ arm64 ] + runs-on: ${{ matrix.os }} + name: ${{ matrix.os }} / Node ${{ matrix.node }} ${{ matrix.arch }} steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - name: Install Dependencies - run: npm ci - - name: Rebuild - run: npm run rebuild - - name: Run Unit - run: npm run unit - - name: Post Unit Test Coverage - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: ./coverage/unit/ - files: lcov.info - flags: unit-tests-${{ matrix.node-version }}-windows-2019 - - name: Run Integration - run: npm run integration - - name: Post Integration Test Coverage - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: ./coverage/integration/ - files: lcov.info - flags: integration-tests-${{ matrix.node-version }}-windows-2019 + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/node_modules + key: ${{ matrix.os }}-${{ matrix.arch }}-node-${{ matrix.node }}-${{ hashFiles('./package.json') }} + - name: Use node ${{ matrix.node }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + architecture: ${{ matrix.arch }} + - name: Install + run: npm install + - name: Unit Test + run: npm run unit + - name: Post Unit Test Coverage + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + directory: ./coverage/unit/ + files: lcov.info + flags: unit-tests-${{ matrix.node }}-${{ matrix.os }}-${{ matrix.arch }} + - name: Integration Test + run: npm run integration + - name: Post Integration Test Coverage + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + directory: ./coverage/integration/ + files: lcov.info + flags: integration-tests-${{ matrix.node }}-${{ matrix.os }}-${{ matrix.arch }} - windows-latest: - runs-on: windows-latest - - # Node 16+ should eventually bundle node-gyp>=8.4.0 to be compatible with Server 2022. - # Once compatible, can remove node-gyp upgrade. + test_linux_arm: + # Skip this group if the PR doesn't originate from the main repo. + # Trying to run this on standard runners is just going to fail due to + # lack of CPU resources. + if: ${{ vars.NR_RUNNER != '' }} strategy: matrix: - node-version: [16.x, 18.x, 20.x] - + node: [ 16, 18, 20 ] + runs-on: ${{ vars.NR_RUNNER }} + name: Linux / Node ${{ matrix.node }} arm64 + timeout-minutes: 15 steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - name: Install Dependencies - run: npm ci - - name: Rebuild - run: npm run rebuild - - name: Run Unit - run: npm run unit - - name: Post Unit Test Coverage - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: ./coverage/unit/ - files: lcov.info - flags: unit-tests-${{ matrix.node-version }}-windows-latest - - name: Run Integration - run: npm run integration - - name: Post Integration Test Coverage - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: ./coverage/integration/ - files: lcov.info - flags: integration-tests-${{ matrix.node-version }}-windows-latest + - name: Checkout + uses: actions/checkout@v4 + - name: Compute cache key + run: echo -e "CACHE_KEY=$(shasum -a 256 package.json | cut -f1 -d ' ')" >> "$GITHUB_ENV" + - name: Restore modules cache + id: cache_restore + uses: actions/cache/restore@v4 + with: + path: ${{ github.workspace }}/node_modules + key: linux-arm-node-${{ matrix.node }}-${{ env.CACHE_KEY }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: arm64 + - uses: docker/setup-buildx-action@v3 + - uses: docker/build-push-action@v5 + with: + context: . + build-args: | + NODE_VERSION=${{ matrix.node }} + file: linux_arm.dockerfile + tags: linux_arm:node-${{ matrix.node }} + load: true + push: false + platforms: linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + - name: Run test + uses: addnab/docker-run-action@v3 + with: + image: linux_arm:node-${{ matrix.node }} + options: --platform linux/arm64 -v ${{ github.workspace }}:/host + run: | + cp -R /host/node_modules . 2>/dev/null + rm -rf /host/node_modules 2>/dev/null + # npm install will fail on Node 18 every time unless we use this + # very odd fix: + # https://github.com/npm/cli/issues/4652#issuecomment-1126672629 + npm install --verbose --maxsockets 1 + cp -R node_modules /host/ + npm run unit + # Skipping integration until we can get native arm64 runners + # npm run integration + - name: Update modules cache + uses: actions/cache/save@v4 + # We always want to run this step even if the "test" step failed. + if: ${{ steps.cache_restore.outputs.cache-hit != 'true' && !cancelled() }} + with: + path: ${{ github.workspace }}/node_modules + key: linux-arm-node-${{ matrix.node }}-${{ env.CACHE_KEY }} diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 358eb5c..2ac17bc 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -1,11 +1,227 @@ name: Create Release +on: + workflow_dispatch: + inputs: + changelog_file: + description: Name of changelog file. + type: string + required: false + default: CHANGELOG.md -on: [workflow_dispatch] - + dry_run: + description: Build package but don't tag or publish. + type: boolean + required: true + default: false jobs: - tag-and-publish: - uses: newrelic/node-newrelic/.github/workflows/release-creation.yml@main - with: - changelog_file: CHANGELOG.md - secrets: - npm_token: ${{ secrets.NODE_AGENT_NPM_TOKEN }} + build_x86_x64: + strategy: + matrix: + os: [ ubuntu-latest, windows-latest ] + node: [ 16, 18, 20 ] + arch: [ x86, x64 ] + exclude: + # Ubuntu does not ship x86 builds. + - { os: ubuntu-latest, arch: x86 } + runs-on: ${{ matrix.os }} + name: ${{ matrix.os }} / Node ${{ matrix.node }} ${{ matrix.arch }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Use node ${{ matrix.node }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + architecture: ${{ matrix.arch }} + - uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/node_modules + key: ${{ matrix.os }}-${{ matrix.arch }}-node-${{ matrix.node }}-${{ hashFiles('./package.json') }} + - name: Install + run: npm install + - name: Build + run: npm run build + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.node }} + path: prebuilds + + build_macos_arm: + strategy: + matrix: + os: [ macos-14 ] + node: [ 16, 18, 20 ] + arch: [ arm64 ] + runs-on: ${{ matrix.os }} + name: ${{ matrix.os }} / Node ${{ matrix.node }} ${{ matrix.arch }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/node_modules + key: ${{ matrix.os }}-${{ matrix.arch }}-node-${{ matrix.node }}-${{ hashFiles('./package.json') }} + - name: Use node ${{ matrix.node }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + architecture: ${{ matrix.arch }} + - name: Install + run: npm install + - name: Build + run: npm run build + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.node }} + path: prebuilds + + build_linux_arm: + # Skip this group if the PR doesn't originate from the main repo. + # Trying to run this on standard runners is just going to fail due to + # lack of CPU resources. + if: ${{ vars.NR_RUNNER != '' }} + strategy: + matrix: + node: [ 16, 18, 20 ] + runs-on: ${{ vars.NR_RUNNER }} + name: Linux / Node ${{ matrix.node }} arm64 + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Compute cache key + run: echo -e "CACHE_KEY=$(shasum -a 256 package.json | cut -f1 -d ' ')" >> "$GITHUB_ENV" + - name: Restore modules cache + id: cache_restore + uses: actions/cache/restore@v4 + with: + path: ${{ github.workspace }}/node_modules + key: linux-arm-node-${{ matrix.node }}-${{ env.CACHE_KEY }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: arm64 + - uses: docker/setup-buildx-action@v3 + - uses: docker/build-push-action@v5 + with: + context: . + build-args: | + NODE_VERSION=${{ matrix.node }} + file: linux_arm.dockerfile + tags: linux_arm:node-${{ matrix.node }} + load: true + push: false + platforms: linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + - name: Run build + uses: addnab/docker-run-action@v3 + with: + image: linux_arm:node-${{ matrix.node }} + options: --platform linux/arm64 -v ${{ github.workspace }}:/host + run: | + cp -R /host/node_modules . 2>/dev/null + rm -rf /host/node_modules 2>/dev/null + # npm install will fail on Node 18 every time unless we use this + # very odd fix: + # https://github.com/npm/cli/issues/4652#issuecomment-1126672629 + npm install --verbose --maxsockets 1 + cp -R node_modules /host/ + npm run build + cp -R prebuilds /host/ + - name: Update modules cache + uses: actions/cache/save@v4 + # We always want to run this step even if the "test" step failed. + if: ${{ steps.cache_restore.outputs.cache-hit != 'true' && !cancelled() }} + with: + path: ${{ github.workspace }}/node_modules + key: linux-arm-node-${{ matrix.node }}-${{ env.CACHE_KEY }} + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: linux-arm64-${{ matrix.node }} + path: prebuilds + + package: + needs: [ build_x86_x64, build_macos_arm, build_linux_arm ] + runs-on: ubuntu-latest + name: Create package + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + - run: | + mkdir prebuilds + rm -f .gitignore + - uses: actions/download-artifact@v4 + with: + path: ${{ github.workspace }}/prebuilds + merge-multiple: true + - run: echo -e "PKG_VERSION=$(jq -r .version < package.json)" >> "$GITHUB_ENV" + - run: npm pack + - uses: actions/upload-artifact@v4 + with: + name: npm-module + path: newrelic-native-metrics-${{ env.PKG_VERSION }}.tgz + + # Our typical flow looks like: + # 1. prepare-release workflow + # 2. create-release workflow + # + # We can't do that (easily) because access to artifacts from other workflows + # are difficult to access (requires a personal access token). See + # https://github.com/actions/download-artifact#download-artifacts-from-other-workflow-runs-or-repositories + # + # Given that, we need to replicate all of our create-release steps inline + # here. + tag_release: + if: ${{ inputs.dry_run == false }} + needs: [ package ] + runs-on: ubuntu-latest + name: Tag Release + steps: + - uses: actions/checkout@v4 + # We need access to the prep scripts in the node-newrelic repo. + - uses: actions/checkout@v4 + with: + repository: newrelic/node-newrelic + path: agent-repo + - uses: actions/setup-node@v4 + - run: | + # Install agent-repo dependencies. + npm ci --prefix agent-repo + - name: Configure GitHub Credentials + run: | + git config user.name ${GITHUB_ACTOR} + git config user.email gh-actions-${GITHUB_ACTOR}@github.com + - name: Create Release Tag + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + node ./agent-repo/bin/create-release-tag.js --branch ${{ github.ref }} --repo ${{ github.repository }} --workflows test.yml,prepare-release.yml + - name: Get Created Tag + id: get_tag + run: echo "latest_tag=$(git describe --tags --abbrev=0)" >> ${GITHUB_OUTPUT} + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + node ./agent-repo/bin/create-github-release.js --tag ${{ steps.get_tag.outputs.latest_tag }} --repo ${{ github.repository }} --changelog ${{ inputs.changelog_file }} + + publish: + if: ${{ inputs.dry_run == false }} + needs: [ tag_release ] + runs-on: ubuntu-latest + name: Publish Package + steps: + - uses: actions/setup-node@v4 + with: + registry-url: 'https://registry.npmjs.org' + - uses: actions/download-artifact@v4 + with: + name: npm-module + - run: echo -e "PKG_NAME=$(ls -1A *.tgz | head -n 1)" >> "$GITHUB_ENV" + - run: npm publish --access=public ${PKG_NAME} + env: + NODE_AUTH_TOKEN: ${{ secrets.NODE_AGENT_NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 7adbe30..60101b8 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ coverage # Compiled binary addons (http://nodejs.org/api/addons.html) build/ lib/binary +prebuilds/ # Dependency directory # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 274522a..3b5b1b8 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -14,8 +14,9 @@ code, the source code can be found at [https://github.com/newrelic/node-native-m **[dependencies](#dependencies)** -* [https-proxy-agent](#https-proxy-agent) * [nan](#nan) +* [node-gyp-build](#node-gyp-build) +* [prebuildify](#prebuildify) * [semver](#semver) **[devDependencies](#devDependencies)** @@ -44,42 +45,84 @@ code, the source code can be found at [https://github.com/newrelic/node-native-m ## dependencies -### https-proxy-agent +### nan -This product includes source derived from [https-proxy-agent](https://github.com/TooTallNate/node-https-proxy-agent) ([v5.0.1](https://github.com/TooTallNate/node-https-proxy-agent/tree/v5.0.1)), distributed under the [MIT License](https://github.com/TooTallNate/node-https-proxy-agent/blob/v5.0.1/README.md): +This product includes source derived from [nan](https://github.com/nodejs/nan) ([v2.18.0](https://github.com/nodejs/nan/tree/v2.18.0)), distributed under the [MIT License](https://github.com/nodejs/nan/blob/v2.18.0/LICENSE.md): ``` -MIT License +The MIT License (MIT) -Copyright (c) +Copyright (c) 2018 [NAN contributors]() Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ``` -### nan +### node-gyp-build -This product includes source derived from [nan](https://github.com/nodejs/nan) ([v2.17.0](https://github.com/nodejs/nan/tree/v2.17.0)), distributed under the [MIT License](https://github.com/nodejs/nan/blob/v2.17.0/LICENSE.md): +This product includes source derived from [node-gyp-build](https://github.com/prebuild/node-gyp-build) ([v4.8.0](https://github.com/prebuild/node-gyp-build/tree/v4.8.0)), distributed under the [MIT License](https://github.com/prebuild/node-gyp-build/blob/v4.8.0/LICENSE): ``` The MIT License (MIT) -Copyright (c) 2018 [NAN contributors]() +Copyright (c) 2017 Mathias Buus -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +``` + +### prebuildify + +This product includes source derived from [prebuildify](https://github.com/prebuild/prebuildify) ([v6.0.0](https://github.com/prebuild/prebuildify/tree/v6.0.0)), distributed under the [MIT License](https://github.com/prebuild/prebuildify/blob/v6.0.0/LICENSE): + +``` +The MIT License (MIT) + +Copyright (c) 2017 Mathias Buus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. ``` ### semver -This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.5.2](https://github.com/npm/node-semver/tree/v7.5.2)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.5.2/LICENSE): +This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.6.0](https://github.com/npm/node-semver/tree/v7.6.0)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.6.0/LICENSE): ``` The ISC License @@ -538,7 +581,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ### async -This product includes source derived from [async](https://github.com/caolan/async) ([v3.2.4](https://github.com/caolan/async/tree/v3.2.4)), distributed under the [MIT License](https://github.com/caolan/async/blob/v3.2.4/LICENSE): +This product includes source derived from [async](https://github.com/caolan/async) ([v3.2.5](https://github.com/caolan/async/tree/v3.2.5)), distributed under the [MIT License](https://github.com/caolan/async/blob/v3.2.5/LICENSE): ``` Copyright (c) 2010-2018 Caolan McMahon @@ -565,7 +608,7 @@ THE SOFTWARE. ### aws-sdk -This product includes source derived from [aws-sdk](https://github.com/aws/aws-sdk-js) ([v2.1354.0](https://github.com/aws/aws-sdk-js/tree/v2.1354.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js/blob/v2.1354.0/LICENSE.txt): +This product includes source derived from [aws-sdk](https://github.com/aws/aws-sdk-js) ([v2.1566.0](https://github.com/aws/aws-sdk-js/tree/v2.1566.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js/blob/v2.1566.0/LICENSE.txt): ``` @@ -775,7 +818,7 @@ This product includes source derived from [aws-sdk](https://github.com/aws/aws-s ### c8 -This product includes source derived from [c8](https://github.com/bcoe/c8) ([v8.0.0](https://github.com/bcoe/c8/tree/v8.0.0)), distributed under the [ISC License](https://github.com/bcoe/c8/blob/v8.0.0/LICENSE.txt): +This product includes source derived from [c8](https://github.com/bcoe/c8) ([v8.0.1](https://github.com/bcoe/c8/tree/v8.0.1)), distributed under the [ISC License](https://github.com/bcoe/c8/blob/v8.0.1/LICENSE.txt): ``` Copyright (c) 2017, Contributors @@ -797,12 +840,12 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ### eslint-config-prettier -This product includes source derived from [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) ([v8.5.0](https://github.com/prettier/eslint-config-prettier/tree/v8.5.0)), distributed under the [MIT License](https://github.com/prettier/eslint-config-prettier/blob/v8.5.0/LICENSE): +This product includes source derived from [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) ([v8.10.0](https://github.com/prettier/eslint-config-prettier/tree/v8.10.0)), distributed under the [MIT License](https://github.com/prettier/eslint-config-prettier/blob/v8.10.0/LICENSE): ``` The MIT License (MIT) -Copyright (c) 2017, 2018, 2019, 2020, 2021, 2022 Simon Lydell and contributors +Copyright (c) 2017, 2018, 2019, 2020, 2021, 2022, 2023 Simon Lydell and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -989,7 +1032,7 @@ SOFTWARE. ### lockfile-lint -This product includes source derived from [lockfile-lint](https://github.com/lirantal/lockfile-lint) ([v4.9.6](https://github.com/lirantal/lockfile-lint/tree/v4.9.6)), distributed under the [Apache-2.0 License](https://github.com/lirantal/lockfile-lint/blob/v4.9.6/LICENSE): +This product includes source derived from [lockfile-lint](https://github.com/lirantal/lockfile-lint) ([v4.13.2](https://github.com/lirantal/lockfile-lint/tree/v4.13.2)), distributed under the [Apache-2.0 License](https://github.com/lirantal/lockfile-lint/blob/v4.13.2/LICENSE): ``` @@ -1187,7 +1230,7 @@ This product includes source derived from [lockfile-lint](https://github.com/lir ### nock -This product includes source derived from [nock](https://github.com/nock/nock) ([v13.2.9](https://github.com/nock/nock/tree/v13.2.9)), distributed under the [MIT License](https://github.com/nock/nock/blob/v13.2.9/LICENSE): +This product includes source derived from [nock](https://github.com/nock/nock) ([v13.5.4](https://github.com/nock/nock/tree/v13.5.4)), distributed under the [MIT License](https://github.com/nock/nock/blob/v13.5.4/LICENSE): ``` MIT License @@ -1216,7 +1259,7 @@ SOFTWARE. ### prettier -This product includes source derived from [prettier](https://github.com/prettier/prettier) ([v2.8.1](https://github.com/prettier/prettier/tree/v2.8.1)), distributed under the [MIT License](https://github.com/prettier/prettier/blob/v2.8.1/LICENSE): +This product includes source derived from [prettier](https://github.com/prettier/prettier) ([v2.8.8](https://github.com/prettier/prettier/tree/v2.8.8)), distributed under the [MIT License](https://github.com/prettier/prettier/blob/v2.8.8/LICENSE): ``` # Prettier license @@ -1246,7 +1289,7 @@ Repository: ---------------------------------------- -### @babel/code-frame@v7.16.7 +### @babel/code-frame@v7.18.6 License: MIT By: The Babel Team @@ -1277,7 +1320,7 @@ Repository: ---------------------------------------- -### @babel/helper-validator-identifier@v7.18.6 +### @babel/helper-validator-identifier@v7.19.1 License: MIT By: The Babel Team @@ -1308,7 +1351,7 @@ Repository: ---------------------------------------- -### @babel/highlight@v7.16.10 +### @babel/highlight@v7.18.6 License: MIT By: The Babel Team @@ -1339,7 +1382,7 @@ Repository: ---------------------------------------- -### @babel/parser@v7.20.1 +### @babel/parser@v7.21.3 License: MIT By: The Babel Team @@ -1558,14 +1601,14 @@ License: MIT ---------------------------------------- -### @typescript-eslint/types@v5.45.0 +### @typescript-eslint/types@v5.55.0 License: MIT Repository: > MIT License > -> Copyright (c) 2019 TypeScript ESLint and other contributors +> Copyright (c) 2019 typescript-eslint and other contributors > > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal @@ -1587,7 +1630,7 @@ Repository: ---------------------------------------- -### @typescript-eslint/typescript-estree@v5.45.0 +### @typescript-eslint/typescript-estree@v5.55.0 License: BSD-2-Clause Repository: @@ -1602,11 +1645,11 @@ Repository: > Redistribution and use in source and binary forms, with or without > modification, are permitted provided that the following conditions are met: > -> * Redistributions of source code must retain the above copyright -> notice, this list of conditions and the following disclaimer. -> * Redistributions in binary form must reproduce the above copyright -> notice, this list of conditions and the following disclaimer in the -> documentation and/or other materials provided with the distribution. +> - Redistributions of source code must retain the above copyright +> notice, this list of conditions and the following disclaimer. +> - Redistributions in binary form must reproduce the above copyright +> notice, this list of conditions and the following disclaimer in the +> documentation and/or other materials provided with the distribution. > > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -1621,14 +1664,14 @@ Repository: ---------------------------------------- -### @typescript-eslint/visitor-keys@v5.45.0 +### @typescript-eslint/visitor-keys@v5.55.0 License: MIT Repository: > MIT License > -> Copyright (c) 2019 TypeScript ESLint and other contributors +> Copyright (c) 2019 typescript-eslint and other contributors > > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal @@ -1650,7 +1693,7 @@ Repository: ---------------------------------------- -### acorn@v8.8.0 +### acorn@v8.8.1 License: MIT Repository: @@ -2464,14 +2507,15 @@ By: Jon Schlinkert ---------------------------------------- -### defaults@v1.0.3 +### defaults@v1.0.4 License: MIT By: Elijah Insua -Repository: +Repository: > The MIT License (MIT) > +> Copyright (c) 2022 Sindre Sorhus > Copyright (c) 2015 Elijah Insua > > Permission is hereby granted, free of charge, to any person obtaining a copy @@ -2494,7 +2538,7 @@ Repository: ---------------------------------------- -### del@v6.0.0 +### del@v6.1.1 License: MIT By: Sindre Sorhus @@ -2612,7 +2656,7 @@ Repository: ---------------------------------------- -### editorconfig-to-prettier@v0.2.0 +### editorconfig-to-prettier@v1.0.0 License: ISC By: Joseph Frazier @@ -2932,7 +2976,7 @@ By: Toru Nagashima ---------------------------------------- -### espree@v9.4.0 +### espree@v9.4.1 License: BSD-2-Clause By: Nicholas C. Zakas @@ -3040,7 +3084,7 @@ Repository: ---------------------------------------- -### fast-glob@v3.2.11 +### fast-glob@v3.2.12 License: MIT By: Denis Malinochkin @@ -3099,7 +3143,7 @@ Repository: ---------------------------------------- -### fastq@v1.13.0 +### fastq@v1.14.0 License: ISC By: Matteo Collina @@ -3273,7 +3317,7 @@ By: Roy Riojas ---------------------------------------- -### flatted@v3.2.5 +### flatted@v3.2.7 License: ISC By: Andrea Giammarchi @@ -3448,7 +3492,7 @@ By: Sindre Sorhus ---------------------------------------- -### glob@v7.2.0 +### glob@v7.2.3 License: ISC By: Isaac Z. Schlueter @@ -3518,14 +3562,14 @@ By: Sindre Sorhus ---------------------------------------- -### graceful-fs@v4.2.9 +### graceful-fs@v4.2.10 License: ISC Repository: > The ISC License > -> Copyright (c) Isaac Z. Schlueter, Ben Noordhuis, and Contributors +> Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors > > Permission to use, copy, modify, and/or distribute this software for any > purpose with or without fee is hereby granted, provided that the above @@ -3678,36 +3722,6 @@ By: Titus Wormer ---------------------------------------- -### html-void-elements@v2.0.1 - -License: MIT -By: Titus Wormer - -> (The MIT License) -> -> Copyright (c) 2016 Titus Wormer -> -> Permission is hereby granted, free of charge, to any person obtaining -> a copy of this software and associated documentation files (the -> 'Software'), to deal in the Software without restriction, including -> without limitation the rights to use, copy, modify, merge, publish, -> distribute, sublicense, and/or sell copies of the Software, and to -> permit persons to whom the Software is furnished to do so, subject to -> the following conditions: -> -> The above copyright notice and this permission notice shall be -> included in all copies or substantial portions of the Software. -> -> THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ----------------------------------------- - ### human-signals@v3.0.1 License: Apache-2.0 @@ -3947,6 +3961,36 @@ Repository: ---------------------------------------- +### ignore@v5.2.4 + +License: MIT +By: kael +Repository: + +> Copyright (c) 2013 Kael Zhang , contributors +> http://kael.me/ +> +> Permission is hereby granted, free of charge, to any person obtaining +> a copy of this software and associated documentation files (the +> "Software"), to deal in the Software without restriction, including +> without limitation the rights to use, copy, modify, merge, publish, +> distribute, sublicense, and/or sell copies of the Software, and to +> permit persons to whom the Software is furnished to do so, subject to +> the following conditions: +> +> The above copyright notice and this permission notice shall be +> included in all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +---------------------------------------- + ### import-fresh@v3.3.0 License: MIT @@ -4178,7 +4222,7 @@ Repository: ---------------------------------------- -### is-core-module@v2.8.1 +### is-core-module@v2.11.0 License: MIT By: Jordan Harband @@ -4614,7 +4658,7 @@ By: Kat Marchán ---------------------------------------- -### json5@v2.2.1 +### json5@v2.2.2 License: MIT By: Aseem Kishore @@ -5878,7 +5922,7 @@ By: Jon Schlinkert ---------------------------------------- -### resolve@v1.22.0 +### resolve@v1.22.1 License: MIT By: James Halliday @@ -6087,6 +6131,30 @@ Repository: ---------------------------------------- +### semver@v7.3.8 + +License: ISC +By: GitHub Inc. +Repository: + +> The ISC License +> +> Copyright (c) Isaac Z. Schlueter and Contributors +> +> Permission to use, copy, modify, and/or distribute this software for any +> purpose with or without fee is hereby granted, provided that the above +> copyright notice and this permission notice appear in all copies. +> +> THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +> WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +> MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +> ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +> WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +> IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------- + ### semver-compare@v1.0.0 License: MIT @@ -6518,7 +6586,7 @@ Repository: ---------------------------------------- -### typescript@v4.9.3 +### typescript@v5.0.2 License: Apache-2.0 By: Microsoft Corp. @@ -7269,7 +7337,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### tap -This product includes source derived from [tap](https://github.com/tapjs/node-tap) ([v16.3.7](https://github.com/tapjs/node-tap/tree/v16.3.7)), distributed under the [ISC License](https://github.com/tapjs/node-tap/blob/v16.3.7/LICENSE): +This product includes source derived from [tap](https://github.com/tapjs/node-tap) ([v16.3.10](https://github.com/tapjs/node-tap/tree/v16.3.10)), distributed under the [ISC License](https://github.com/tapjs/node-tap/blob/v16.3.10/LICENSE): ``` The ISC License diff --git a/binding.gyp b/binding.gyp index 7cd9fc4..04e58a7 100644 --- a/binding.gyp +++ b/binding.gyp @@ -1,4 +1,9 @@ { + "variables": { + # Node.js >= 20 seems to have issues with this. Search + # "'openssl_fips' is not defined while evaluating" for many results. + "openssl_fips": 0 + }, "targets": [{ "target_name": "native_metrics", "sources": [ diff --git a/build.js b/build.js new file mode 100644 index 0000000..7cb4462 --- /dev/null +++ b/build.js @@ -0,0 +1,61 @@ +#!/usr/bin/env node +/* + * Copyright 2024 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict' + +// If we are going to support Windows, we need some way to cobble together +// the build command that is portable. In other words, we can't rely on a +// Bash subshell, `$(node...)`, to get the current Node version to provide +// to `--target`. So we'll use the scripting language at our disposal that is +// cross platform 😃 + +const fs = require('fs/promises') +const path = require('path') +const { spawn } = require('child_process') + +main() + .then(() => { + // eslint-disable-next-line no-console + console.log('build done') + }) + .catch((error) => { + // eslint-disable-next-line no-console + console.error(error) + }) + +async function main() { + await fs.rm(path.join(__dirname, 'build'), { force: true, recursive: true }) + await fs.rm(path.join(__dirname, 'prebuilds'), { force: true, recursive: true }) + + const bin = process.argv[0] + const args = [ + path.join(__dirname, 'node_modules', 'prebuildify', 'bin.js'), + '--strip', + // We want to apply all tags since we are building across multiple + // Node.js versions. If we don't we will stop on the binaries during + // packaging. + '--tag-uv', + '--tag-armv', + '--tag-libc', + // We need to be explicit here so that the ABI tag gets applied. + '--napi=false', + '--target', + `node@${process.versions.node}` + ] + + return new Promise((res, rej) => { + const proc = spawn(bin, args) + proc.stderr.pipe(process.stderr) + proc.stdout.pipe(process.stdout) + + proc.on('close', (code, signal) => { + if (code !== 0) { + return rej(Error(`failed with code ${code} and signal ${signal}`)) + } + res() + }) + }) +} diff --git a/index.js b/index.js index bce5315..19e41a9 100644 --- a/index.js +++ b/index.js @@ -7,8 +7,7 @@ const EventEmitter = require('events').EventEmitter const util = require('util') -const preBuild = require('./lib/pre-build') -const natives = preBuild.load('native_metrics') +const natives = require('node-gyp-build')(__dirname) const semver = require('semver') const DEFAULT_TIMEOUT = 15 * 1000 // 15 seconds diff --git a/lib/common.js b/lib/common.js deleted file mode 100644 index d9ebd28..0000000 --- a/lib/common.js +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2021 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' -const path = require('path') -const common = module.exports - -const pkgRoot = path.resolve(__dirname, '..') -common.BUILD_PATH = path.resolve(pkgRoot, './build/Release') -common.REMOTE_PATH = process.env.NR_NATIVE_METRICS_REMOTE_PATH || 'nodejs_agent/builds/' -common.IS_WIN = process.platform === 'win32' - -common.parseArgs = function parseArgs(_argv, _opts) { - const args = [] - for (let i = 0; i < _argv.length; ++i) { - if (/^--/.test(_argv[i])) { - _opts[_argv[i].substr(2)] = true - } else { - args.push(_argv[i]) - } - } - return args -} - -common.logStart = function logStart(cmd) { - /* eslint-disable no-console */ - console.log( - [ - '============================================================================', - `Attempting ${cmd} in native-metrics module. Please note that this is an`, - 'OPTIONAL dependency, and any resultant errors in this process will not', - 'affect the general performance of the New Relic agent, but event loop and', - 'garbage collection metrics will not be collected for the Node VMs page.', - '============================================================================', - '' - ].join('\n') - /* eslint-enable no-console */ - ) -} - -common.logFinish = function logFinish(cmd, target, err) { - /* eslint-disable no-console */ - if (err) { - console.error(`Failed to execute native-metrics ${cmd}: ${err.message}\n`) - - console.error( - [ - 'Failed install of this OPTIONAL dependency will not impact the general performance', - 'of the New Relic Node.js agent. You may safely run in production. Your application', - 'will be missing event loop and garbage collection metrics for the Node VMs page.', - 'To capture Node event loop and GC metrics, please resolve issues and reinstall.' - ].join('\n') - ) - - // eslint-disable-next-line no-process-exit - process.exit(1) - } else { - console.log(cmd + ' successful: ' + common.getFileName(target)) - } - /* eslint-enable no-console */ -} - -common.getFileName = function getFileName(target) { - const abi = process.versions.modules - const arch = process.arch - const platform = process.platform - const pkg = require('../package') - const pkgName = pkg.name.replace(/[^\w]/g, '_') - const pkgVersion = pkg.version.toString().replace(/[^\w]/g, '_') - - if (!abi || !arch || !target || !platform || !pkg || !pkgName || !pkgVersion) { - throw new Error('Missing information for naming compiled binary.') - } - - /** - * Electron forks Node and has its own custom ABI versions. Because of this, - * the ABI version.included in the binary filename causes issues related to - * mismatched Node versions. A quick + temporary fix for this is to strip out - * the ABI name for suspected Electron builds. Tools such as `electron-builder` - * and `electron-rebuild` will include environment variables to work with - * node-gyp. We can look at those env vars to see if they have been patched - * to contain the word 'electron'. - * For more context: https://github.com/newrelic/node-native-metrics/pull/75 - * It's worth pointing out that this is a patch and not a solution as this will - * have other (minor) repercussions - */ - if ( - (process.env.npm_config_runtime || '').includes('electron') || - (process.env.npm_config_disturl || '').includes('electron') - ) { - return [pkgName, pkgVersion, target, platform, arch].join('-') - } - - return [pkgName, pkgVersion, target, abi, platform, arch].join('-') -} - -common.getPackageFileName = function getPackageFileName(target) { - return common.getFileName(target) + '.gz' -} - -common.getBinFileName = function getBinFileName(target) { - return common.getFileName(target) + '.node' -} diff --git a/lib/gyp-utils.js b/lib/gyp-utils.js deleted file mode 100644 index 3f8b329..0000000 --- a/lib/gyp-utils.js +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2023 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' -const utils = module.exports -const fs = require('fs') -const path = require('path') -const cp = require('child_process') -const { IS_WIN } = require('./common') - -/** - * This code heavily borrows from node-pre-gyp. - * https://github.com/mapbox/node-pre-gyp/blob/e0b3b6/lib/util/compile.js#L18-L55 - */ -utils.findNodeGyp = function findNodeGyp() { - // First, look for it in the NPM environment variable. - let gypPath = null - if (process.env.npm_config_node_gyp) { - try { - gypPath = process.env.npm_config_node_gyp - fs.accessSync(gypPath) - return gypPath - } catch (err) { - // This method failed, hopefully the next will succeed... - } - } - - // Next, see if the package is installed somewhere. - try { - // eslint-disable-next-line node/no-missing-require - const gypPkgPath = require.resolve('node-gyp') - gypPath = path.resolve(gypPkgPath, '../../bin/node-gyp.js') - fs.accessSync(gypPath) - return gypPath - } catch (err) { - // This method failed, hopefully the next will succeed... - } - - // Then look for it in NPM's install location. - try { - // eslint-disable-next-line node/no-missing-require - const npmPkgPath = require.resolve('npm') - gypPath = path.resolve(npmPkgPath, '../../node_modules/node-gyp/bin/node-gyp.js') - fs.accessSync(gypPath) - return gypPath - } catch (err) { - // This method failed, hopefully the next will succeed... - } - - // All of that failed, now look for it next to node itself. - const nodeNpmPkgPath = path.resolve(process.execPath, '../../lib/node_modules/npm/') - gypPath = path.join(nodeNpmPkgPath, 'node_modules/node-gyp/bin/node-gyp.js') - try { - fs.accessSync(gypPath) - return gypPath - } catch { - return null - } -} - -utils.extractGypCmd = function extractGypCmd(args) { - let cmd = null - const gyp = utils.findNodeGyp() - if (gyp) { - args.unshift(gyp) // push_front - cmd = process.execPath - } else { - cmd = IS_WIN ? 'node-gyp.cmd' : 'node-gyp' - } - - return cmd -} - -utils.gypVersion = function gypVersion() { - const args = ['-v'] - const cmd = utils.extractGypCmd(args) - const child = cp.spawnSync(cmd, args) - const match = /v(\d+\.\d+\.\d+)/.exec(child.stdout) - return match && match[1] -} - -utils.execGyp = function execGyp(args, opts) { - const cmd = utils.extractGypCmd(args) - const spawnOpts = {} - if (!opts.quiet) { - spawnOpts.stdio = [0, 1, 2] - } - console.log('> ' + cmd + ' ' + args.join(' ')) // eslint-disable-line no-console - - const child = cp.spawnSync(cmd, args, spawnOpts) - - if (child.status !== 0) { - throw new Error('Command exited with non-zero code: ' + child.status) - } -} diff --git a/lib/pre-build.js b/lib/pre-build.js deleted file mode 100644 index 24f03b6..0000000 --- a/lib/pre-build.js +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -// This file is largely based upon the work done for node-pre-gyp. We are not -// using that module directly due to issues we've run into with the intricacies -// of various node and npm versions that we must support. -// https://www.npmjs.com/package/node-pre-gyp - -// XXX This file must not have any deps. This file will run during the install -// XXX step of the module and we are _not_ guaranteed that the dependencies have -// XXX already installed. Core modules are okay. -const fs = require('fs/promises') -const http = require('http') -const https = require('https') -const os = require('os') -const path = require('path') -const semver = require('semver') -const zlib = require('zlib') -const ProxyAgent = require('https-proxy-agent') - -const { - getBinFileName, - getPackageFileName, - parseArgs, - logStart, - logFinish, - BUILD_PATH, - REMOTE_PATH, - IS_WIN -} = require('./common') -const { execGyp, gypVersion } = require('./gyp-utils') - -const CPU_COUNT = os.cpus().length -const DOWNLOAD_HOST = - process.env.NR_NATIVE_METRICS_DOWNLOAD_HOST || 'https://download.newrelic.com/' - -const opts = {} -const preBuild = module.exports - -preBuild.load = function load(target) { - return require(path.join(BUILD_PATH, getBinFileName(target))) -} - -preBuild.makePath = async function makePath() { - const accessRights = fs.constants.R_OK | fs.constants.W_OK - - try { - await fs.access(BUILD_PATH, accessRights) - } catch (err) { - if (err?.code !== 'ENOENT') { - // It exists but we don't have read+write access! This is a problem. - throw new Error(`Do not have access to '${BUILD_PATH}': ${err}`) - } - - await fs.mkdir(BUILD_PATH, { recursive: true }) - } -} - -preBuild.build = function build(target, rebuild) { - const HAS_OLD_NODE_GYP_ARGS_FOR_WINDOWS = semver.lt(gypVersion() || '0.0.0', '3.7.0') - - if (IS_WIN && HAS_OLD_NODE_GYP_ARGS_FOR_WINDOWS) { - target = '/t:' + target - } - - const cmds = rebuild ? ['clean', 'configure'] : ['configure'] - - execGyp(cmds, opts) - - const jobs = Math.round(CPU_COUNT / 2) - execGyp(['build', '-j', jobs, target], opts) -} - -preBuild.moveBuild = async function moveBuild(target) { - const filePath = path.join(BUILD_PATH, target + '.node') - const destination = path.join(BUILD_PATH, getBinFileName(target)) - await fs.rename(filePath, destination) -} - -function setupRequest() { - let client = null - const options = {} - const proxyHost = process.env.NR_NATIVE_METRICS_PROXY_HOST - - if (proxyHost) { - options.agent = new ProxyAgent(proxyHost) - client = /^https:/.test(proxyHost) ? https : http - } else if (DOWNLOAD_HOST.startsWith('https:')) { - client = https - } else { - // eslint-disable-next-line no-console - console.log(`Falling back to http, please consider enabling SSL on ${DOWNLOAD_HOST}`) - client = http - } - - return { client, options } -} - -preBuild.download = async function download(target) { - const fileName = getPackageFileName(target) - const url = DOWNLOAD_HOST + REMOTE_PATH + fileName - const { client, options } = setupRequest() - - return new Promise((resolve, reject) => { - client.get(url, options, function handleResponse(res) { - if (res.statusCode === 404) { - reject(new Error('No pre-built artifacts for your OS/architecture.')) - } else if (res.statusCode !== 200) { - reject(new Error('Failed to download ' + url + ': code ' + res.statusCode)) - } - - const unzip = zlib.createGunzip() - const buffers = [] - let size = 0 - - res.on('error', function httpError(err) { - reject(new Error('Failed to download ' + url + ': ' + err.message)) - }) - - unzip.on('error', function unzipError(err) { - reject(new Error('Failed to unzip ' + url + ': ' + err.message)) - }) - - res.pipe(unzip).on('data', function onResData(data) { - buffers.push(data) - size += data.length - }) - - unzip.on('end', function onResEnd() { - resolve(Buffer.concat(buffers, size)) - }) - - res.resume() - }) - }) -} - -preBuild.saveDownload = async function saveDownload(target, data) { - await preBuild.makePath() - - const filePath = path.join(BUILD_PATH, getBinFileName(target)) - await fs.writeFile(filePath, data) -} - -preBuild.install = async function install(target) { - const noBuild = opts['no-build'] || process.env.NR_NATIVE_METRICS_NO_BUILD - const noDownload = opts['no-download'] || process.env.NR_NATIVE_METRICS_NO_DOWNLOAD - - if (noDownload && !noBuild) { - // If NR_NATIVE_METRICS_NO_DOWNLOAD env var is specified, jump straight to building - preBuild.build(target, true) - return await preBuild.moveBuild(target) - } - - // Try the download path first, if that fails try building if config allows - try { - const data = await preBuild.download(target) - await preBuild.saveDownload(target, data) - } catch (err) { - // eslint-disable-next-line no-console - console.log(`Download error: ${err.message}, falling back to build`) - - if (noBuild) { - throw new Error('Building is disabled by configuration') - } - - preBuild.build(target, true) - await preBuild.moveBuild(target) - } -} - -preBuild.executeCli = async function executeCli(cmd, target) { - logStart(cmd) - if (cmd === 'build' || cmd === 'rebuild') { - try { - preBuild.build(target, cmd === 'rebuild') - await preBuild.moveBuild(target) - logFinish(cmd, target) - } catch (err) { - logFinish(cmd, target, err) - } - } else if (cmd === 'install') { - try { - await preBuild.install(target) - logFinish(cmd, target) - } catch (err) { - logFinish(cmd, target, err) - } - } -} - -if (require.main === module) { - const [, , cmd, target] = parseArgs(process.argv, opts) - preBuild.executeCli(cmd, target) -} diff --git a/lib/upload.js b/lib/upload.js deleted file mode 100644 index 229b594..0000000 --- a/lib/upload.js +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2021 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' -const { - getBinFileName, - parseArgs, - getPackageFileName, - logStart, - logFinish, - BUILD_PATH, - REMOTE_PATH -} = require('./common') -const fs = require('fs') -const zlib = require('zlib') -const path = require('path') - -// XXX This is the one external dep allowed by this module. The aws-sdk must -// XXX be a dev-dep of the module and uploading should only be done after -// XXX installing. -// XXX AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must be set in the environment. -const AWS = require('aws-sdk') -const s3 = new AWS.S3() -const S3_BUCKET = 'nr-downloads-main' -const CMD = 'upload' - -if (require.main === module) { - const [, , target] = parseArgs(process.argv, {}) - logStart(CMD) - upload(target, logFinish.bind(this, CMD, target)) -} - -function upload(target, cb) { - const zip = zlib.createGzip() - const binPath = path.join(BUILD_PATH, getBinFileName(target)) - fs.createReadStream(binPath).pipe(zip) - - const key = path.join(REMOTE_PATH, getPackageFileName(target)) - - s3.upload( - { - Bucket: S3_BUCKET, - Key: key, - Body: zip - }, - function s3UploadCb(err) { - if (err) { - cb(new Error('Failed to upload file: ' + err.message)) - } else { - cb() - } - } - ) -} - -// exporting upload function to mock outgoing calls -module.exports = upload diff --git a/linux_arm.dockerfile b/linux_arm.dockerfile new file mode 100644 index 0000000..2360417 --- /dev/null +++ b/linux_arm.dockerfile @@ -0,0 +1,12 @@ +ARG NODE_VERSION +FROM node:${NODE_VERSION}-slim + +RUN apt update && apt install -y python3 build-essential + +WORKDIR /app +RUN mkdir /app/src +COPY ./src/ /app/src/ +COPY ./tests/ /app/tests/ +COPY binding.gyp index.js package.json package-lock.json build.js /app/ + +CMD npm install && npm test diff --git a/package-lock.json b/package-lock.json index 49c97d3..1e0f767 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,9 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "https-proxy-agent": "^5.0.1", - "nan": "^2.17.0", + "nan": "^2.18.0", + "node-gyp-build": "^4.8.0", + "prebuildify": "^6.0.0", "semver": "^7.5.2" }, "devDependencies": { @@ -2965,38 +2966,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -3235,7 +3204,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -3288,7 +3256,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -3299,7 +3266,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "funding": [ { "type": "github", @@ -3548,8 +3514,7 @@ "node_modules/chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "node_modules/clean-stack": { "version": "3.0.1", @@ -3969,7 +3934,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "dependencies": { "once": "^1.4.0" } @@ -4460,6 +4424,14 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execspawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/execspawn/-/execspawn-1.0.1.tgz", + "integrity": "sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg==", + "dependencies": { + "util-extend": "^1.0.1" + } + }, "node_modules/extract-stack": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-1.0.0.tgz", @@ -4685,8 +4657,7 @@ "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "node_modules/fs-exists-cached": { "version": "1.0.0", @@ -5024,39 +4995,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -5093,8 +5031,7 @@ "node_modules/ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "node_modules/ignore": { "version": "4.0.6", @@ -5152,8 +5089,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/is-arguments": { "version": "1.1.1", @@ -6231,7 +6167,6 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6263,8 +6198,7 @@ "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, "node_modules/module-not-found-error": { "version": "1.0.1", @@ -6297,9 +6231,9 @@ "dev": true }, "node_modules/nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -6391,6 +6325,27 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/node-abi": { + "version": "3.55.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.55.0.tgz", + "integrity": "sha512-uPEjtyh2tFEvWYt4Jw7McOD5FPcHkcxm/tHZc5PWaDB3JYq0rGFUbgaAK+CT5pYpQddBfsZVWI08OwoRfdfbcQ==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -6705,7 +6660,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -6993,7 +6947,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -7128,6 +7081,34 @@ "semver-compare": "^1.0.0" } }, + "node_modules/prebuildify": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/prebuildify/-/prebuildify-6.0.0.tgz", + "integrity": "sha512-DEvK4C3tcimIp7Pzqbs036n9i6CTKGp1XVEpMnr4wV3enKU5sBogPP+lP3KZw7993i42bXnsd5eIxAXQ566Cqw==", + "dependencies": { + "execspawn": "^1.0.1", + "minimist": "^1.2.5", + "mkdirp-classic": "^0.5.3", + "node-abi": "^3.3.0", + "npm-run-path": "^3.1.0", + "pump": "^3.0.0", + "tar-fs": "^2.1.0" + }, + "bin": { + "prebuildify": "bin.js" + } + }, + "node_modules/prebuildify/node_modules/npm-run-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", + "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -7209,7 +7190,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -7296,7 +7276,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7494,7 +7473,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -7823,7 +7801,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -10124,7 +10101,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -10136,7 +10112,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -10383,14 +10358,12 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/util-extend": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "dev": true + "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==" }, "node_modules/uuid": { "version": "8.0.0", @@ -10537,8 +10510,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "3.0.3", @@ -12894,29 +12866,6 @@ "dev": true, "requires": {} }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -13101,8 +13050,7 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "basic-auth-parser": { "version": "0.0.2", @@ -13135,7 +13083,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -13146,7 +13093,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -13308,8 +13254,7 @@ "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "clean-stack": { "version": "3.0.1", @@ -13643,7 +13588,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "requires": { "once": "^1.4.0" } @@ -13998,6 +13942,14 @@ "strip-final-newline": "^2.0.0" } }, + "execspawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/execspawn/-/execspawn-1.0.1.tgz", + "integrity": "sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg==", + "requires": { + "util-extend": "^1.0.1" + } + }, "extract-stack": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-1.0.0.tgz", @@ -14170,8 +14122,7 @@ "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "fs-exists-cached": { "version": "1.0.0", @@ -14422,30 +14373,6 @@ } } }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "requires": { - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -14467,8 +14394,7 @@ "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "ignore": { "version": "4.0.6", @@ -14511,8 +14437,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "is-arguments": { "version": "1.1.1", @@ -15326,8 +15251,7 @@ "minimist": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "dev": true + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" }, "minipass": { "version": "3.3.6", @@ -15350,8 +15274,7 @@ "mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, "module-not-found-error": { "version": "1.0.1", @@ -15378,9 +15301,9 @@ "dev": true }, "nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", + "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==" }, "natural-compare": { "version": "1.4.0", @@ -15462,6 +15385,19 @@ } } }, + "node-abi": { + "version": "3.55.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.55.0.tgz", + "integrity": "sha512-uPEjtyh2tFEvWYt4Jw7McOD5FPcHkcxm/tHZc5PWaDB3JYq0rGFUbgaAK+CT5pYpQddBfsZVWI08OwoRfdfbcQ==", + "requires": { + "semver": "^7.3.5" + } + }, + "node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==" + }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -15714,7 +15650,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "requires": { "wrappy": "1" } @@ -15933,8 +15868,7 @@ "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "path-parse": { "version": "1.0.7", @@ -16040,6 +15974,30 @@ "semver-compare": "^1.0.0" } }, + "prebuildify": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/prebuildify/-/prebuildify-6.0.0.tgz", + "integrity": "sha512-DEvK4C3tcimIp7Pzqbs036n9i6CTKGp1XVEpMnr4wV3enKU5sBogPP+lP3KZw7993i42bXnsd5eIxAXQ566Cqw==", + "requires": { + "execspawn": "^1.0.1", + "minimist": "^1.2.5", + "mkdirp-classic": "^0.5.3", + "node-abi": "^3.3.0", + "npm-run-path": "^3.1.0", + "pump": "^3.0.0", + "tar-fs": "^2.1.0" + }, + "dependencies": { + "npm-run-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", + "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", + "requires": { + "path-key": "^3.0.0" + } + } + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -16097,7 +16055,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -16160,7 +16117,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -16299,8 +16255,7 @@ "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "sax": { "version": "1.2.1", @@ -16562,7 +16517,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, "requires": { "safe-buffer": "~5.2.0" } @@ -18069,7 +18023,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, "requires": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -18081,7 +18034,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, "requires": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -18270,14 +18222,12 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "util-extend": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", - "dev": true + "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==" }, "uuid": { "version": "8.0.0", @@ -18390,8 +18340,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "write-file-atomic": { "version": "3.0.3", diff --git a/package.json b/package.json index 9a81ee0..bf5c837 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,7 @@ "description": "A module for generating metrics from V8.", "main": "index.js", "scripts": { - "build": "node ./lib/pre-build build native_metrics", - "clean": "node-gyp clean", - "rebuild": "node ./lib/pre-build rebuild native_metrics", - "upload": "node ./lib/upload native_metrics", + "build": "node ./build.js", "lint": "eslint .", "lint:fix": "eslint . --fix", "lint:lockfile": "lockfile-lint --path package-lock.json --type npm --allowed-hosts npm --validate-https --validate-integrity", @@ -15,8 +12,8 @@ "integration": "c8 -o ./coverage/integration tap --timeout 360000 --jobs=1 --no-coverage tests/integration/*.tap.js", "native": "node tests/native/*.js", "test": "npm run unit && npm run integration", - "install": "node ./lib/pre-build.js install native_metrics", - "prepare": "husky install", + "install": "node-gyp-build", + "prepare": "husky install || true", "third-party-updates": "oss third-party manifest && oss third-party notices && git add THIRD_PARTY_NOTICES.md third_party_manifest.json" }, "repository": { @@ -100,17 +97,17 @@ "tap": "^16.3.7" }, "dependencies": { - "https-proxy-agent": "^5.0.1", - "nan": "^2.17.0", + "nan": "^2.18.0", + "node-gyp-build": "^4.8.0", + "prebuildify": "^6.0.0", "semver": "^7.5.2" }, "files": [ "index.js", + "build.js", + "prebuilds/**/*", "src/*cpp", "src/*.hpp", - "lib/common.js", - "lib/pre-build.js", - "lib/gyp-utils.js", "binding.gyp", "*.md" ] diff --git a/tests/integration/download-server.js b/tests/integration/download-server.js deleted file mode 100644 index c004961..0000000 --- a/tests/integration/download-server.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2022 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' -const fs = require('fs') -const http = require('http') -const path = require('path') -const zlib = require('zlib') -const { execSync } = require('child_process') -const BINARY_TMP = '/var/tmp/' - -function findBinary() { - return fs.readdirSync(BINARY_TMP).filter((file) => { - return file.endsWith('.node') - }) -} - -// building module to serve in the server instead of grabbing from -// download.newrelic.com -execSync(`node ./lib/pre-build rebuild native_metrics`) -// moving module to avoid a passing test on download -// even though the file existing in the build/Release folder -execSync(`mv ./build/Release/*.node ${BINARY_TMP}`) -const [file] = findBinary() -const binaryPath = path.join(BINARY_TMP, file) -// remove build folder as it is recreated during install/download -execSync(`rm -rf ./build`) - -const server = http.createServer(function (req, res) { - const raw = fs.createReadStream(binaryPath) - res.writeHead(200, { 'content-encoding': 'gzip' }) - raw.pipe(zlib.createGzip()).pipe(res) -}) - -server.listen(function () { - const port = server.address().port - // eslint-disable-next-line no-console - console.log(`Started download server on port: ${port}`) - process.send && process.send({ msg: 'STARTED', port }) -}) diff --git a/tests/integration/pre-build.tap.js b/tests/integration/pre-build.tap.js deleted file mode 100644 index 95748e5..0000000 --- a/tests/integration/pre-build.tap.js +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2021 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const tap = require('tap') -const { execSync, fork } = require('child_process') -const path = require('path') -const fs = require('fs') -const os = require('os') -const CMDS = ['build', 'rebuild', 'install'] -const platform = os.platform() -const NO_PREBUILTS = ['darwin', 'win32'] -const { IS_WIN } = require('../../lib/common') - -/** - * Locates the pre-built native metrics binary in `./build/Release` folder. - */ -function findBinary() { - try { - return fs.readdirSync('./build/Release').filter((file) => { - return file.endsWith('.node') - }) - } catch (err) { - if (err?.code === 'ENOENT') { - return [] - } - } -} - -/** - * Helper to wait for a child process to send an expected message. - * - * @param {EventEmitter} child forked process - * @param {string} msg expected messeage from child process - */ -function waitFor(child, msg) { - return new Promise((resolve) => { - child.on('message', handler) - - function handler(message) { - if (message.msg === msg) { - child.removeListener('message', handler) - resolve(message.port) - } - } - }) -} - -tap.test('pre-build commands', function (t) { - t.beforeEach(() => { - execSync('rm -rf ./build') - }) - - CMDS.forEach((cmd) => { - t.test(`${cmd} test`, function (t) { - execSync(`node ./lib/pre-build ${cmd} native_metrics`) - const binary = findBinary() - t.match( - binary, - /_newrelic_native_metrics-\d{1,3}_\d{1,3}_\d{1,3}-native_metrics.*\.node/, - 'should build binary' - ) - t.end() - }) - }) - - t.test('failed download', { skip: !NO_PREBUILTS.includes(platform) }, function (t) { - t.throws( - () => execSync('node ./lib/pre-build --no-build install native_metrics'), - `should error when trying to download on ${platform}` - ) - const binary = findBinary() - t.same(binary, [], `should not download binary for ${platform}`) - t.end() - }) - - // no reason to test downloading on windows. only reason we test on mac is so - // you can run these tests locally - t.test('download', { skip: IS_WIN }, async function (t) { - const downloadServer = fork(path.join(__dirname, './download-server.js')) - const port = await waitFor(downloadServer, 'STARTED') - process.env.NR_NATIVE_METRICS_DOWNLOAD_HOST = `http://localhost:${port}/` - execSync('node ./lib/pre-build --no-build install native_metrics') - const binary = findBinary() - t.match( - binary, - /_newrelic_native_metrics-\d{1,3}_\d{1,3}_\d{1,3}-native_metrics.*\.node/, - 'should download binary' - ) - downloadServer.kill() - }) - - // no reason to test downloading on windows. only reason we test on mac is so - // you can run these tests locally - t.test('download with proxy', { skip: IS_WIN }, async function (t) { - const proxyServer = fork(path.join(__dirname, './proxy-server.js')) - const downloadServer = fork(path.join(__dirname, './download-server.js')) - const proxyPromise = waitFor(proxyServer, 'STARTED') - const downloadPromise = waitFor(downloadServer, 'STARTED') - const [proxyPort, downloadPort] = await Promise.all([proxyPromise, downloadPromise]) - - process.env.NR_NATIVE_METRICS_PROXY_HOST = `http://localhost:${proxyPort}` - process.env.NR_NATIVE_METRICS_DOWNLOAD_HOST = `http://localhost:${downloadPort}/` - execSync(`node ./lib/pre-build --no-build install native_metrics`) - const binary = findBinary() - t.match( - binary, - /_newrelic_native_metrics-\d{1,3}_\d{1,3}_\d{1,3}-native_metrics.*\.node/, - 'should download binary' - ) - proxyServer.kill() - downloadServer.kill() - }) - - t.test('invalid cmd(no-op)', function (t) { - execSync('node ./lib/pre-build invalid-command native_metrics') - const binary = findBinary() - t.same(binary, [], 'should not build with invalid command') - t.end() - }) - - t.end() -}) diff --git a/tests/integration/proxy-server.js b/tests/integration/proxy-server.js deleted file mode 100644 index 7a25757..0000000 --- a/tests/integration/proxy-server.js +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2022 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const http = require('http') -const proxyServer = require('@newrelic/proxy') - -async function startServer() { - const server = proxyServer(http.createServer()) - const port = await new Promise((resolve) => { - server.listen(() => { - const listenerPort = server.address().port - // eslint-disable-next-line no-console - console.log(`Started proxy on port: ${listenerPort}`) - resolve(listenerPort) - }) - }) - process.send && process.send({ msg: 'STARTED', port }) -} - -startServer().catch((err) => { - // eslint-disable-next-line no-console - console.error(err) - // eslint-disable-next-line no-process-exit - process.exit(1) -}) diff --git a/tests/integration/server.tap.js b/tests/integration/server.tap.js deleted file mode 100644 index a27a798..0000000 --- a/tests/integration/server.tap.js +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const tap = require('tap') -const http = require('http') -const segs = require('segfault-handler') -const { execSync } = require('child_process') - -const RUN_TIME = 5 * 60 * 1000 // 5 minutes -const TEST_TIMEOUT = RUN_TIME + 10000 - -segs.registerHandler('crash.log') - -tap.test('server soak test', function (t) { - t.comment('Installing native metrics') - const { output, elapsed } = installNativeMetrics() - t.comment('Finished installing') - t.comment('Output: ', output) - - // We increase the timeout by the install time to avoid counting against the - // execution time threshold while still setting up in the test execution. - const newTimeout = TEST_TIMEOUT + elapsed - t.comment('Setting new timeout: ', newTimeout) - t.setTimeout(newTimeout) - - const natives = require('../../')() - t.comment('Running test server for ' + RUN_TIME + 'ms') - const server = http.createServer(function (req, res) { - res.write('ok') - res.end() - }) - - server.on('close', function () { - t.pass('server closed') - natives.unbind() - }) - server.listen(0, function () { - t.pass('server started') - }) - const port = server.address().port - - let keepSending = true - setTimeout(sendRequest, 1000) - setTimeout(function () { - t.comment('stopping') - keepSending = false - }, RUN_TIME) - - setInterval(function () { - if (!natives.getGCMetrics()) { - t.fail('should have readable gc metrics') - } - if (!natives.getLoopMetrics()) { - t.fail('should have readable loop metrics') - } - }, 5000).unref() - - function sendRequest() { - http.get('http://localhost:' + port, function (res) { - if (!res || res.statusCode !== 200) { - t.ok(res, 'should have a response object') - t.equal(res.statusCode, 200, 'should have a successful response') - } - - if (keepSending) { - setTimeout(sendRequest, 10) - } else { - server.close(function (err) { - t.error(err, 'should not fail to close') - t.end() - }) - } - }) - } -}) - -function installNativeMetrics() { - const start = new Date() - const output = execSync(`node ./lib/pre-build install native_metrics`, { encoding: 'utf-8' }) - - const elapsed = new Date() - start - return { - elapsed, - output - } -} diff --git a/tests/integration/upload.tap.js b/tests/integration/upload.tap.js deleted file mode 100644 index d157bf7..0000000 --- a/tests/integration/upload.tap.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2021 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const tap = require('tap') -const { execSync } = require('child_process') -const upload = require('../../lib/upload') -const nock = require('nock') - -tap.test('upload', function (t) { - t.before(() => { - nock.disableNetConnect() - }) - - t.teardown(() => { - nock.enableNetConnect() - }) - - t.test('success', (t) => { - nock('https://nr-downloads-main.s3.amazonaws.com:443') - .put(/nodejs_agent/) - .reply(200) - execSync('rm -rf ./build/Release/*') - execSync(`node ./lib/pre-build build native_metrics`) - upload('native_metrics', t.end) - }) - - t.test('failure', (t) => { - nock('https://nr-downloads-main.s3.amazonaws.com:443') - .put(/nodejs_agent/) - .reply(404) - execSync('rm -rf ./build/Release/*') - execSync(`node ./lib/pre-build build native_metrics`) - upload('native_metrics', (err) => { - t.ok(err, 'should error when not returning 200') - t.end() - }) - }) - - t.end() -}) diff --git a/tests/unit/common.tap.js b/tests/unit/common.tap.js deleted file mode 100644 index cf5ae5a..0000000 --- a/tests/unit/common.tap.js +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2021 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const tap = require('tap') -const sinon = require('sinon') -const common = require('../../lib/common') - -tap.test('common tests', (t) => { - t.before(() => { - sinon.stub(console, 'log') - sinon.stub(console, 'error') - }) - - tap.test('parseArgs', (t) => { - const argv = ['arg1', 'arg2', '--opt1', '--opt2'] - const opts = {} - t.test('set args with -- as opts', (t) => { - common.parseArgs(argv, opts) - t.same(opts, { opt1: true, opt2: true }, 'should set opts properly') - t.end() - }) - - t.test('set all args without -- as args', (t) => { - const args = common.parseArgs(argv, opts) - t.same(args, ['arg1', 'arg2'], 'should set args properly') - t.end() - }) - t.end() - }) - - tap.test('logStart', (t) => { - common.logStart('install') - // eslint-disable-next-line no-console - const [[msg]] = console.log.args - t.match(msg, /Attempting install in native-metrics/, 'should log msg with proper command') - t.end() - }) - - tap.test('logFinish', (t) => { - t.test('log error', (t) => { - const err = new Error('unit test error') - sinon.stub(process, 'exit') - common.logFinish('build', 'target', err) - // eslint-disable-next-line no-console - const [[msg]] = console.error.args - - t.equal( - msg.trim(), - `Failed to execute native-metrics build: ${err.message}`, - 'should log console.error message' - ) - t.equal(process.exit.args[0][0], 1, 'should exit with code 1') - process.exit.restore() - t.end() - }) - - t.test('log success', (t) => { - common.logFinish('build', 'target') - // eslint-disable-next-line no-console - const [, [msg]] = console.log.args - t.match(msg, /build successful: _newrelic_native_metrics/, 'should log finish message') - t.end() - }) - - t.end() - }) - - tap.test('getFileName', (t) => { - t.test('missing target', (t) => { - t.throws( - () => common.getFileName(), - 'Missing information for naming compiled binary.', - 'should throw error when missing target' - ) - t.end() - }) - - t.test('electron naming', (t) => { - process.env.npm_config_runtime = 'electron' - const name = common.getFileName('target') - // eslint-disable-next-line max-len - const regex = new RegExp( - `_newrelic_native_metrics-\\d{1,3}_\\d{1,3}_\\d{1,3}-target-${process.platform}-${process.arch}` - ) - t.match(name, regex, 'should match electron convention') - t.end() - }) - - t.test('standard naming', (t) => { - process.env.npm_config_runtime = '' - const name = common.getFileName('target') - // eslint-disable-next-line max-len - const regex = new RegExp( - `_newrelic_native_metrics-\\d{1,3}_\\d{1,3}_\\d{1,3}-target-${process.versions.modules}-${process.platform}-${process.arch}` - ) - t.match(name, regex, 'should match electron convention') - t.end() - }) - t.end() - }) - - tap.test('getPackageFileName', (t) => { - const name = common.getPackageFileName('target') - t.ok(name.endsWith('.gz'), 'should end with .gz') - t.end() - }) - - tap.test('getBinFileName', (t) => { - const name = common.getBinFileName('target') - t.ok(name.endsWith('.node'), 'should end with .node') - t.end() - }) - - t.end() -}) diff --git a/tests/unit/gyp-utils.tap.js b/tests/unit/gyp-utils.tap.js deleted file mode 100644 index a484605..0000000 --- a/tests/unit/gyp-utils.tap.js +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2023 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const tap = require('tap') -const sinon = require('sinon') -const cp = require('child_process') -const common = require('../../lib/common') -const gypUtils = require('../../lib/gyp-utils') -const fs = require('fs') - -tap.test('gyp-utils tests', (t) => { - t.autoend() - - t.test('findNodeGyp', (t) => { - t.autoend() - - t.test('should return gyp path from `process.env.npm_config_node_gyp`', (t) => { - const expectedPath = `${process.cwd()}/index.js` - process.env.npm_config_node_gyp = expectedPath - t.teardown(() => { - delete process.env.npm_config_node_gyp - }) - - const gypPath = gypUtils.findNodeGyp() - t.equal(gypPath, expectedPath) - t.end() - }) - - t.test('should return null if all lookups fail`', (t) => { - sinon.stub(fs, 'accessSync') - fs.accessSync.throws(new Error('nope, could not access')) - const gypPath = gypUtils.findNodeGyp() - t.equal(gypPath, null) - t.end() - }) - }) - - t.test('extractGypCmd', (t) => { - t.autoend() - let sandbox - - t.beforeEach(() => { - sandbox = sinon.createSandbox() - sandbox.stub(gypUtils, 'findNodeGyp') - }) - - t.afterEach(() => { - sandbox.restore() - }) - - t.test('should add gyp path to args and return cmd', (t) => { - const gypPath = '/path/to/node-gyp' - gypUtils.findNodeGyp.returns(gypPath) - const args = ['-v'] - const cmd = gypUtils.extractGypCmd(args) - t.equal(cmd, process.execPath) - t.ok(args.length === 2, 'should add an arg') - t.equal(args[0], gypPath, 'gypPath be prepended to args array') - t.end() - }) - - t.test('should not add gyp path to args if it is not found', (t) => { - const args = ['arg1'] - gypUtils.findNodeGyp.returns(false) - const cmd = gypUtils.extractGypCmd(args) - t.equal(cmd, common.IS_WIN ? 'node-gyp.cmd' : 'node-gyp') - t.ok(args.length === 1, 'should not add an arg') - t.end() - }) - }) - - t.test('gypVersion', (t) => { - t.autoend() - let sandbox - - t.beforeEach(() => { - sandbox = sinon.createSandbox() - sandbox.stub(cp, 'spawnSync') - }) - - t.afterEach(() => { - sandbox.restore() - }) - - t.test('should find gyp version', (t) => { - const expectedVersion = '10.0.0' - cp.spawnSync.returns({ stdout: `v${expectedVersion}` }) - const version = gypUtils.gypVersion() - t.equal(version, expectedVersion) - t.end() - }) - - t.test('should not return version if stdout does not match vx.x.x', (t) => { - cp.spawnSync.returns({ stdout: 'random stuff' }) - const version = gypUtils.gypVersion() - t.notOk(version) - t.end() - }) - }) - - t.test('execGyp', (t) => { - t.autoend() - let sandbox - - t.beforeEach(() => { - sandbox = sinon.createSandbox() - sandbox.stub(cp, 'spawnSync') - }) - - t.afterEach(() => { - sandbox.restore() - }) - - t.test('should return if status is 0', (t) => { - cp.spawnSync.returns({ status: 0 }) - gypUtils.execGyp([], {}) - t.same( - cp.spawnSync.args[0][2], - { stdio: [0, 1, 2] }, - 'spawnSync opts should include stdio if not quiet' - ) - t.end() - }) - - t.test('should not set stdio on spawn if opts.quiet is true', (t) => { - const opts = { quiet: true } - cp.spawnSync.returns({ status: 0 }) - gypUtils.execGyp([], opts) - t.same(cp.spawnSync.args[0][2], {}, 'spawn opts should include stdio if not quiet') - t.end() - }) - - t.test('should return with error if spawn fails', (t) => { - const expectedErr = new Error('failed to spawn gyp cmd') - cp.spawnSync.throws(expectedErr) - t.throws(() => gypUtils.execGyp([], {}), expectedErr) - t.end() - }) - - t.test('should return with error if code is not 0', (t) => { - cp.spawnSync.returns({ status: 1 }) - t.throws(() => gypUtils.execGyp([], {}), 'Command exited with non-zero code: 1') - t.end() - }) - }) -}) diff --git a/tests/unit/loop-metrics.tap.js b/tests/unit/loop-metrics.tap.js index 6b4f246..bff022e 100644 --- a/tests/unit/loop-metrics.tap.js +++ b/tests/unit/loop-metrics.tap.js @@ -11,7 +11,7 @@ tap.test('Loop Metrics', function (t) { const MICRO_TO_MILLIS = 1e-3 const SPIN_TIME = 2000 const CPU_EPSILON = SPIN_TIME * 0.05 // Allowed fudge factor for CPU times in MS - const metricEmitter = require('../../')() + const metricEmitter = require('../../')({ timeout: 10 }) const testStart = Date.now() t.teardown(function () { @@ -51,38 +51,47 @@ tap.test('Loop Metrics', function (t) { // XXX Keep this as a timeout. On Node v4 it causes an extra period of idle // wait on IO due to a bug in timers. This time should not be counted in // the actual loop time because the process isn't doing anything. - setTimeout(function spinner() { + setTimeout(spinner, 100) + + function spinner() { t.comment('spinning cpu...') const start = Date.now() while (Date.now() - start < SPIN_TIME) {} // Spin the CPU for 2 seconds. // Finally, wait another tick and then check the loop stats. - setTimeout(function () { - metric = metricEmitter.getLoopMetrics() - const testDuration = Date.now() - testStart + CPU_EPSILON - const durationSquare = testDuration * testDuration - const usage = metric.usage + setTimeout(afterSpin, 100) + } - const meanTime = usage.total / usage.count - t.ok( - usage.total * MICRO_TO_MILLIS > SPIN_TIME - CPU_EPSILON, - 'should have total greater than spin time' - ) - t.ok( - usage.total * MICRO_TO_MILLIS <= testDuration, - 'should have total less than wall-clock time' - ) - t.ok(usage.min < meanTime, 'should have min less than the mean usage time') - t.ok(usage.max > meanTime, 'should have max greater than the mean usage time') - t.ok(usage.max * MICRO_TO_MILLIS > SPIN_TIME - CPU_EPSILON, 'should have expected max') - t.ok( - usage.sumOfSquares * MICRO_TO_MILLIS * MICRO_TO_MILLIS < durationSquare, - 'should have expected sumOfSquares' + function afterSpin() { + metric = metricEmitter.getLoopMetrics() + const testDuration = Date.now() - testStart + CPU_EPSILON + const durationSquare = testDuration * testDuration + const usage = metric.usage + + const meanTime = usage.total / usage.count + if (process.arch === 'arm64') { + t.comment( + `{ min: ${usage.min}, max: ${usage.max}, meanTime: ${meanTime}, count: ${usage.count}, total: ${usage.total} }` ) - t.ok(usage.count >= 2, 'should have expected count') + } + t.ok( + usage.total * MICRO_TO_MILLIS > SPIN_TIME - CPU_EPSILON, + 'should have total greater than spin time' + ) + t.ok( + usage.total * MICRO_TO_MILLIS <= testDuration, + 'should have total less than wall-clock time' + ) + t.ok(usage.min <= meanTime, 'should have min less than the mean usage time') + t.ok(usage.max >= meanTime, 'should have max greater than the mean usage time') + t.ok(usage.max * MICRO_TO_MILLIS > SPIN_TIME - CPU_EPSILON, 'should have expected max') + t.ok( + usage.sumOfSquares * MICRO_TO_MILLIS * MICRO_TO_MILLIS < durationSquare, + 'should have expected sumOfSquares' + ) + t.ok(usage.count >= 2, 'should have expected count') - // Done! - t.end() - }, 5) - }, 5) + // Done! + t.end() + } }) diff --git a/tests/unit/pre-build.tap.js b/tests/unit/pre-build.tap.js deleted file mode 100644 index cc14c95..0000000 --- a/tests/unit/pre-build.tap.js +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright 2023 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const tap = require('tap') -const sinon = require('sinon') -const proxyquire = require('proxyquire') -const nock = require('nock') -const zlib = require('zlib') -const { IS_WIN, BUILD_PATH } = require('../../lib/common') - -tap.test('pre-build tests', (t) => { - t.autoend() - - t.test('makePath', (t) => { - t.autoend() - - let mockFsPromiseApi - let preBuild - - t.beforeEach(() => { - mockFsPromiseApi = { - constants: { - R_OK: 4, - W_OK: 2 - }, - access: sinon.stub().resolves(), - mkdir: sinon.stub().resolves() - } - preBuild = proxyquire('../../lib/pre-build', { - 'fs/promises': mockFsPromiseApi - }) - }) - - t.test('should make a nested folder path accordingly if it does not exist', async (t) => { - mockFsPromiseApi.access.rejects({ code: 'ENOENT' }) - await preBuild.makePath() - t.equal(mockFsPromiseApi.mkdir.callCount, 1, 'should have called mkdir') - }) - - t.test('should throw if permissions to path are incorrect', { skip: IS_WIN }, async (t) => { - mockFsPromiseApi.access.rejects({ code: 'EACCESS' }) - t.equal(mockFsPromiseApi.mkdir.callCount, 0, 'should not have called mkdir') - t.rejects( - preBuild.makePath(), - new Error(`Do not have access to '${BUILD_PATH}'`), - 'should error with EACCESS' - ) - }) - - t.test('should throw if creating the nested folder path fails', async (t) => { - mockFsPromiseApi.access.rejects({ code: 'ENOENT' }) - const expectedError = new Error('whoops') - mockFsPromiseApi.mkdir.rejects(expectedError) - - t.rejects(preBuild.makePath(), expectedError, 'should have rejected with expectedError') - }) - - t.test('should not create the nested folder path if it exists and is accessible', async (t) => { - await preBuild.makePath() - t.equal(mockFsPromiseApi.mkdir.callCount, 0, 'should not have called mkdir') - }) - }) - - t.test('build', (t) => { - t.autoend() - const gypStub = {} - let sandbox - let build - - t.beforeEach(() => { - sandbox = sinon.createSandbox() - gypStub.execGyp = sandbox.stub() - ;({ build } = proxyquire('../../lib/pre-build', { - './gyp-utils': gypStub - })) - }) - - t.afterEach(() => { - sandbox.restore() - }) - - t.test('should run clean configure if rebuild is true', (t) => { - gypStub.execGyp.returns(null) - build('target', true) - - t.ok(gypStub.execGyp.callCount, 2, 'should call execGyp twice') - t.same(gypStub.execGyp.args[0][0], ['clean', 'configure']) - t.equal(gypStub.execGyp.args[1][0][3], 'target') - t.end() - }) - - t.test('should run configure and build if rebuild is false', (t) => { - gypStub.execGyp.returns(null) - build('target', false) - - t.ok(gypStub.execGyp.callCount, 2, 'should call execGyp twice') - t.same(gypStub.execGyp.args[0][0], ['configure']) - t.end() - }) - - t.test('should return error if configure fails', (t) => { - const expectedErr = new Error('failed to execute cmd') - gypStub.execGyp.throws(expectedErr) - t.throws(() => build('target', false), expectedErr) - t.end() - }) - - t.test('should return error if build fails', (t) => { - const expectedErr = new Error('failed to execute cmd') - gypStub.execGyp.onCall(0).returns(null) - gypStub.execGyp.onCall(1).throws(expectedErr) - t.throws(() => build('target', false), expectedErr) - t.end() - }) - }) - - t.test('moveBuild', (t) => { - t.autoend() - - let mockFsPromiseApi - let preBuild - - t.beforeEach(() => { - mockFsPromiseApi = { - rename: sinon.stub().resolves() - } - preBuild = proxyquire('../../lib/pre-build', { - 'fs/promises': mockFsPromiseApi - }) - }) - - t.test('should move build accordingly', async (t) => { - await preBuild.moveBuild('target') - t.equal(mockFsPromiseApi.rename.callCount, 1) - }) - }) - - t.test('download', (t) => { - t.autoend() - let sandbox - let preBuild - - t.before(() => { - nock.disableNetConnect() - }) - - t.beforeEach(() => { - sandbox = sinon.createSandbox() - preBuild = proxyquire('../../lib/pre-build', { - 'fs/promises': {} - }) - }) - - t.afterEach(() => { - sandbox.restore() - delete process.env.NR_NATIVE_METRICS_PROXY_HOST - delete process.env.NR_NATIVE_METRICS_DOWNLOAD_HOST - }) - - t.test('should download and unzip file accordingly', async (t) => { - const expectedData = Buffer.from('testing', 'utf-8') - const file = zlib.gzipSync(expectedData) - nock('https://download.newrelic.com/').get(/.*/).reply(200, file) - - const data = await preBuild.download('test') - t.same(data, expectedData) - }) - - t.test('should return error if 404 occurs', async (t) => { - nock('https://download.newrelic.com/').get(/.*/).reply(404) - - t.rejects( - preBuild.download('test'), - new Error('No pre-built artifacts for your OS/architecture.'), - 'should reject with expected error' - ) - }) - - t.test('should return failed to download error if response is not 200 nor 404', async (t) => { - nock('https://download.newrelic.com/').get(/.*/).reply(500) - - t.rejects( - preBuild.download('test'), - new Error('Failed to download'), - 'should reject with expected error' - ) - }) - - t.test('should fail if it cannot unzip', async (t) => { - const expectedData = Buffer.from('testing', 'utf-8') - nock('https://download.newrelic.com/').get(/.*/).reply(200, expectedData) - - t.rejects( - preBuild.download('test'), - new Error('Failed to unzip'), - 'should reject with expected error' - ) - }) - - t.test('should use https proxy host', async (t) => { - process.env.NR_NATIVE_METRICS_PROXY_HOST = 'https://proxy-stuff.com' - const expectedData = Buffer.from('testing', 'utf-8') - const file = zlib.gzipSync(expectedData) - nock('https://download.newrelic.com/').get(/.*/).reply(200, file) - - const data = await preBuild.download('test') - t.same(data, expectedData) - }) - - t.test('should use http proxy host', async (t) => { - process.env.NR_NATIVE_METRICS_PROXY_HOST = 'http://proxy-stuff.com' - const expectedData = Buffer.from('testing', 'utf-8') - const file = zlib.gzipSync(expectedData) - nock('http://download.newrelic.com/').get(/.*/).reply(200, file) - - const data = await preBuild.download('test') - t.same(data, expectedData) - }) - - t.test('should use http download host', async (t) => { - process.env.NR_NATIVE_METRICS_DOWNLOAD_HOST = 'http://fake-stuff.com/' - // busting cache to re-load the env var so it uses a diff host - delete require.cache[require.resolve('../../lib/pre-build')] - const localPreBuild = require('../../lib/pre-build') - const expectedData = Buffer.from('testing', 'utf-8') - const file = zlib.gzipSync(expectedData) - nock('http://fake-stuff.com/').get(/.*/).reply(200, file) - - const data = await localPreBuild.download('test') - t.same(data, expectedData) - }) - }) - - t.test('saveDownload', (t) => { - t.autoend() - let sandbox - let preBuild - let mockFsPromiseApi - - t.beforeEach(() => { - sandbox = sinon.createSandbox() - - mockFsPromiseApi = { - writeFile: sinon.stub().resolves() - } - - preBuild = proxyquire('../../lib/pre-build', { - 'fs/promises': mockFsPromiseApi - }) - - sandbox.stub(preBuild, 'makePath') - }) - - t.afterEach(() => { - sandbox.restore() - }) - - t.test('should write download to appropriate path', async (t) => { - preBuild.makePath.resolves() - await preBuild.saveDownload('target', 'data') - t.equal(mockFsPromiseApi.writeFile.callCount, 1, 'should save download') - }) - - t.test('should return error if creating directory fails', async (t) => { - const expectedErr = new Error('failed to write') - preBuild.makePath.rejects(expectedErr) - - t.rejects( - preBuild.saveDownload('target', 'data'), - expectedErr, - 'should reject with expected error' - ) - }) - }) - - t.test('install', (t) => { - t.autoend() - let sandbox - let mockFsPromiseApi - let preBuild - - t.beforeEach(() => { - sandbox = sinon.createSandbox() - - mockFsPromiseApi = { - rename: sinon.stub().resolves() - } - preBuild = proxyquire('../../lib/pre-build', { - 'fs/promises': mockFsPromiseApi - }) - sandbox.stub(preBuild, 'build') - sandbox.stub(preBuild, 'download') - sandbox.stub(preBuild, 'saveDownload') - sandbox.stub(preBuild, 'moveBuild') - }) - - t.afterEach(() => { - sandbox.restore() - delete process.env.NR_NATIVE_METRICS_NO_BUILD - delete process.env.NR_NATIVE_METRICS_NO_DOWNLOAD - }) - - t.test('should download without building when no-build is specified', async (t) => { - const data = 'foo' - process.env.NR_NATIVE_METRICS_NO_BUILD = true - preBuild.download.resolves(data) - preBuild.saveDownload.resolves() - await preBuild.install('target') - t.equal(preBuild.build.callCount, 0, 'should not build') - t.equal(preBuild.download.callCount, 1, 'should download only') - t.equal(preBuild.saveDownload.callCount, 1, 'should download only') - t.equal(preBuild.saveDownload.args[0][0], 'target') - t.equal(preBuild.saveDownload.args[0][1], data) - }) - - t.test('should build without downloading when no-download is specified', async (t) => { - process.env.NR_NATIVE_METRICS_NO_DOWNLOAD = true - preBuild.build.resolves(null) - preBuild.moveBuild.resolves(null) - await preBuild.install('target') - t.equal(preBuild.build.callCount, 1, 'should build') - t.equal(preBuild.moveBuild.callCount, 1, 'should move build') - t.equal(preBuild.download.callCount, 0, 'should not download') - }) - - t.test('should only download if both env vars are set', async (t) => { - process.env.NR_NATIVE_METRICS_NO_DOWNLOAD = true - process.env.NR_NATIVE_METRICS_NO_BUILD = true - const data = 'foo' - preBuild.download.resolves(data) - preBuild.saveDownload.resolves() - preBuild.build.resolves(null) - preBuild.moveBuild.resolves(null) - - await preBuild.install('target') - - t.equal(preBuild.build.callCount, 0, 'should not build') - t.equal(preBuild.moveBuild.callCount, 0, 'should not move build') - t.equal(preBuild.download.callCount, 1, 'should download') - t.equal(preBuild.saveDownload.callCount, 1, 'should save download') - }) - - t.test('should attempt download first then build if download fails by default', async (t) => { - const data = 'foo' - preBuild.download.resolves(data) - preBuild.saveDownload.rejects(new Error('whoops')) - preBuild.build.resolves(null) - preBuild.moveBuild.resolves(null) - - await preBuild.install('target') - - t.ok(preBuild.download.calledBefore(preBuild.saveDownload), 'should download first') - t.ok(preBuild.saveDownload.calledAfter(preBuild.download), 'should save download second') - - t.ok(preBuild.build.calledAfter(preBuild.saveDownload), 'should build third') - t.ok(preBuild.moveBuild.calledAfter(preBuild.build), 'should move build last') - }) - - t.test('should throw when download fails and noBuild is set', async (t) => { - process.env.NR_NATIVE_METRICS_NO_BUILD = true - const data = 'foo' - preBuild.download.resolves(data) - preBuild.saveDownload.rejects(new Error('whoops')) - preBuild.build.resolves(null) - preBuild.moveBuild.resolves(null) - - t.rejects(preBuild.install('target'), new Error('Building is disabled by configuration')) - }) - - t.test('should fail if save download fails and building is disabled', async (t) => { - process.env.NR_NATIVE_METRICS_NO_BUILD = true - const data = 'foo' - preBuild.download.resolves(data) - preBuild.saveDownload.throws(new Error('saving download failed')) - - t.rejects(preBuild.install('target'), new Error('Building is disabled by configuration')) - - t.equal(preBuild.build.callCount, 0, 'should not build') - t.equal(preBuild.download.callCount, 1, 'should download only') - }) - }) - - t.test('executeCli', (t) => { - t.autoend() - let sandbox - let localPreBuild - let commonStub - - t.beforeEach(() => { - sandbox = sinon.createSandbox() - commonStub = { - logStart: sandbox.stub(), - logFinish: sandbox.stub() - } - localPreBuild = proxyquire('../../lib/pre-build', { - './common': commonStub - }) - sandbox.stub(localPreBuild, 'build') - sandbox.stub(localPreBuild, 'moveBuild') - sandbox.stub(localPreBuild, 'install') - }) - - t.afterEach(() => { - sandbox.restore() - }) - ;['build', 'rebuild'].forEach((cmd) => { - t.test(`should build and move when cmd is '${cmd}'`, async (t) => { - localPreBuild.build.resolves() - localPreBuild.moveBuild.resolves() - await localPreBuild.executeCli(cmd, 'target') - t.equal(localPreBuild.build.callCount, 1, 'should build') - t.equal(localPreBuild.moveBuild.callCount, 1, 'should move build') - t.equal(commonStub.logFinish.callCount, 1, 'should log finish') - }) - }) - - t.test('should call install if cmd is install', async (t) => { - await localPreBuild.executeCli('install', 'target') - t.equal(localPreBuild.install.callCount, 1, 'should call install') - }) - - t.test('should log finish if install fails', async (t) => { - const err = new Error('install failed') - localPreBuild.install.rejects(err) - await localPreBuild.executeCli('install', 'target') - t.equal(localPreBuild.install.callCount, 1, 'should call install') - t.equal(commonStub.logFinish.callCount, 1, 'should log finish') - }) - - t.test('should log finish and not move build if build fails', async (t) => { - const err = new Error('build failed') - localPreBuild.build.throws(err) - localPreBuild.executeCli('build', 'target') - t.equal(localPreBuild.build.callCount, 1, 'should build') - t.equal(localPreBuild.moveBuild.callCount, 0, 'should not move build') - t.equal(commonStub.logFinish.callCount, 1, 'should log finish') - }) - }) -}) diff --git a/third_party_manifest.json b/third_party_manifest.json index c6b051f..1ea1106 100644 --- a/third_party_manifest.json +++ b/third_party_manifest.json @@ -1,44 +1,56 @@ { - "lastUpdated": "Thu Aug 10 2023 16:28:04 GMT-0400 (Eastern Daylight Time)", + "lastUpdated": "Tue Feb 27 2024 10:00:42 GMT-0500 (Eastern Standard Time)", "projectName": "Native Metrics for New Relic Node Agent", "projectUrl": "https://github.com/newrelic/node-native-metrics", "includeOptDeps": false, "includeDev": true, "dependencies": { - "https-proxy-agent@5.0.1": { - "name": "https-proxy-agent", - "version": "5.0.1", - "range": "^5.0.1", - "licenses": "MIT", - "repoUrl": "https://github.com/TooTallNate/node-https-proxy-agent", - "versionedRepoUrl": "https://github.com/TooTallNate/node-https-proxy-agent/tree/v5.0.1", - "licenseFile": "node_modules/https-proxy-agent/README.md", - "licenseUrl": "https://github.com/TooTallNate/node-https-proxy-agent/blob/v5.0.1/README.md", - "licenseTextSource": "spdx", - "publisher": "Nathan Rajlich", - "email": "nathan@tootallnate.net", - "url": "http://n8.io/" - }, - "nan@2.17.0": { + "nan@2.18.0": { "name": "nan", - "version": "2.17.0", - "range": "^2.17.0", + "version": "2.18.0", + "range": "^2.18.0", "licenses": "MIT", "repoUrl": "https://github.com/nodejs/nan", - "versionedRepoUrl": "https://github.com/nodejs/nan/tree/v2.17.0", + "versionedRepoUrl": "https://github.com/nodejs/nan/tree/v2.18.0", "licenseFile": "node_modules/nan/LICENSE.md", - "licenseUrl": "https://github.com/nodejs/nan/blob/v2.17.0/LICENSE.md", + "licenseUrl": "https://github.com/nodejs/nan/blob/v2.18.0/LICENSE.md", "licenseTextSource": "file" }, - "semver@7.5.2": { + "node-gyp-build@4.8.0": { + "name": "node-gyp-build", + "version": "4.8.0", + "range": "^4.8.0", + "licenses": "MIT", + "repoUrl": "https://github.com/prebuild/node-gyp-build", + "versionedRepoUrl": "https://github.com/prebuild/node-gyp-build/tree/v4.8.0", + "licenseFile": "node_modules/node-gyp-build/LICENSE", + "licenseUrl": "https://github.com/prebuild/node-gyp-build/blob/v4.8.0/LICENSE", + "licenseTextSource": "file", + "publisher": "Mathias Buus", + "url": "@mafintosh" + }, + "prebuildify@6.0.0": { + "name": "prebuildify", + "version": "6.0.0", + "range": "^6.0.0", + "licenses": "MIT", + "repoUrl": "https://github.com/prebuild/prebuildify", + "versionedRepoUrl": "https://github.com/prebuild/prebuildify/tree/v6.0.0", + "licenseFile": "node_modules/prebuildify/LICENSE", + "licenseUrl": "https://github.com/prebuild/prebuildify/blob/v6.0.0/LICENSE", + "licenseTextSource": "file", + "publisher": "Mathias Buus", + "url": "@mafintosh" + }, + "semver@7.6.0": { "name": "semver", - "version": "7.5.2", + "version": "7.6.0", "range": "^7.5.2", "licenses": "ISC", "repoUrl": "https://github.com/npm/node-semver", - "versionedRepoUrl": "https://github.com/npm/node-semver/tree/v7.5.2", + "versionedRepoUrl": "https://github.com/npm/node-semver/tree/v7.6.0", "licenseFile": "node_modules/semver/LICENSE", - "licenseUrl": "https://github.com/npm/node-semver/blob/v7.5.2/LICENSE", + "licenseUrl": "https://github.com/npm/node-semver/blob/v7.6.0/LICENSE", "licenseTextSource": "file", "publisher": "GitHub Inc." } @@ -83,53 +95,53 @@ "email": "nathan@tootallnate.net", "url": "http://n8.io/" }, - "async@3.2.4": { + "async@3.2.5": { "name": "async", - "version": "3.2.4", + "version": "3.2.5", "range": "^3.2.2", "licenses": "MIT", "repoUrl": "https://github.com/caolan/async", - "versionedRepoUrl": "https://github.com/caolan/async/tree/v3.2.4", + "versionedRepoUrl": "https://github.com/caolan/async/tree/v3.2.5", "licenseFile": "node_modules/async/LICENSE", - "licenseUrl": "https://github.com/caolan/async/blob/v3.2.4/LICENSE", + "licenseUrl": "https://github.com/caolan/async/blob/v3.2.5/LICENSE", "licenseTextSource": "file", "publisher": "Caolan McMahon" }, - "aws-sdk@2.1354.0": { + "aws-sdk@2.1566.0": { "name": "aws-sdk", - "version": "2.1354.0", + "version": "2.1566.0", "range": "^2.266.1", "licenses": "Apache-2.0", "repoUrl": "https://github.com/aws/aws-sdk-js", - "versionedRepoUrl": "https://github.com/aws/aws-sdk-js/tree/v2.1354.0", + "versionedRepoUrl": "https://github.com/aws/aws-sdk-js/tree/v2.1566.0", "licenseFile": "node_modules/aws-sdk/LICENSE.txt", - "licenseUrl": "https://github.com/aws/aws-sdk-js/blob/v2.1354.0/LICENSE.txt", + "licenseUrl": "https://github.com/aws/aws-sdk-js/blob/v2.1566.0/LICENSE.txt", "licenseTextSource": "file", "publisher": "Amazon Web Services", "url": "https://aws.amazon.com/" }, - "c8@8.0.0": { + "c8@8.0.1": { "name": "c8", - "version": "8.0.0", + "version": "8.0.1", "range": "^8.0.0", "licenses": "ISC", "repoUrl": "https://github.com/bcoe/c8", - "versionedRepoUrl": "https://github.com/bcoe/c8/tree/v8.0.0", + "versionedRepoUrl": "https://github.com/bcoe/c8/tree/v8.0.1", "licenseFile": "node_modules/c8/LICENSE.txt", - "licenseUrl": "https://github.com/bcoe/c8/blob/v8.0.0/LICENSE.txt", + "licenseUrl": "https://github.com/bcoe/c8/blob/v8.0.1/LICENSE.txt", "licenseTextSource": "file", "publisher": "Ben Coe", "email": "ben@npmjs.com" }, - "eslint-config-prettier@8.5.0": { + "eslint-config-prettier@8.10.0": { "name": "eslint-config-prettier", - "version": "8.5.0", + "version": "8.10.0", "range": "^8.3.0", "licenses": "MIT", "repoUrl": "https://github.com/prettier/eslint-config-prettier", - "versionedRepoUrl": "https://github.com/prettier/eslint-config-prettier/tree/v8.5.0", + "versionedRepoUrl": "https://github.com/prettier/eslint-config-prettier/tree/v8.10.0", "licenseFile": "node_modules/eslint-config-prettier/LICENSE", - "licenseUrl": "https://github.com/prettier/eslint-config-prettier/blob/v8.5.0/LICENSE", + "licenseUrl": "https://github.com/prettier/eslint-config-prettier/blob/v8.10.0/LICENSE", "licenseTextSource": "file", "publisher": "Simon Lydell" }, @@ -208,42 +220,42 @@ "publisher": "Andrey Okonetchnikov", "email": "andrey@okonet.ru" }, - "lockfile-lint@4.9.6": { + "lockfile-lint@4.13.2": { "name": "lockfile-lint", - "version": "4.9.6", + "version": "4.13.2", "range": "^4.9.6", "licenses": "Apache-2.0", "repoUrl": "https://github.com/lirantal/lockfile-lint", - "versionedRepoUrl": "https://github.com/lirantal/lockfile-lint/tree/v4.9.6", + "versionedRepoUrl": "https://github.com/lirantal/lockfile-lint/tree/v4.13.2", "licenseFile": "node_modules/lockfile-lint/LICENSE", - "licenseUrl": "https://github.com/lirantal/lockfile-lint/blob/v4.9.6/LICENSE", + "licenseUrl": "https://github.com/lirantal/lockfile-lint/blob/v4.13.2/LICENSE", "licenseTextSource": "file", "publisher": "Liran Tal", "email": "liran.tal@gmail.com", "url": "https://github.com/lirantal" }, - "nock@13.2.9": { + "nock@13.5.4": { "name": "nock", - "version": "13.2.9", + "version": "13.5.4", "range": "^13.1.1", "licenses": "MIT", "repoUrl": "https://github.com/nock/nock", - "versionedRepoUrl": "https://github.com/nock/nock/tree/v13.2.9", + "versionedRepoUrl": "https://github.com/nock/nock/tree/v13.5.4", "licenseFile": "node_modules/nock/LICENSE", - "licenseUrl": "https://github.com/nock/nock/blob/v13.2.9/LICENSE", + "licenseUrl": "https://github.com/nock/nock/blob/v13.5.4/LICENSE", "licenseTextSource": "file", "publisher": "Pedro Teixeira", "email": "pedro.teixeira@gmail.com" }, - "prettier@2.8.1": { + "prettier@2.8.8": { "name": "prettier", - "version": "2.8.1", + "version": "2.8.8", "range": "^2.3.2", "licenses": "MIT", "repoUrl": "https://github.com/prettier/prettier", - "versionedRepoUrl": "https://github.com/prettier/prettier/tree/v2.8.1", + "versionedRepoUrl": "https://github.com/prettier/prettier/tree/v2.8.8", "licenseFile": "node_modules/prettier/LICENSE", - "licenseUrl": "https://github.com/prettier/prettier/blob/v2.8.1/LICENSE", + "licenseUrl": "https://github.com/prettier/prettier/blob/v2.8.8/LICENSE", "licenseTextSource": "file", "publisher": "James Long" }, @@ -284,15 +296,15 @@ "licenseTextSource": "file", "publisher": "Christian Johansen" }, - "tap@16.3.7": { + "tap@16.3.10": { "name": "tap", - "version": "16.3.7", + "version": "16.3.10", "range": "^16.3.7", "licenses": "ISC", "repoUrl": "https://github.com/tapjs/node-tap", - "versionedRepoUrl": "https://github.com/tapjs/node-tap/tree/v16.3.7", + "versionedRepoUrl": "https://github.com/tapjs/node-tap/tree/v16.3.10", "licenseFile": "node_modules/tap/LICENSE", - "licenseUrl": "https://github.com/tapjs/node-tap/blob/v16.3.7/LICENSE", + "licenseUrl": "https://github.com/tapjs/node-tap/blob/v16.3.10/LICENSE", "licenseTextSource": "file", "publisher": "Isaac Z. Schlueter", "email": "i@izs.me",