diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 32b56f58..d798bc7e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -64,33 +64,36 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + if: github.ref == 'refs/heads/master' with: fetch-depth: 0 - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4 + if: github.ref == 'refs/heads/master' with: node-version: ${{ env.NODE_VERSION }} - - if: runner.os == 'Windows' + - if: ${{ runner.os == 'Windows' && github.ref == 'refs/heads/master'}} run: echo "ONLY_DOWNLOAD_PACT_FOR_WINDOWS=true" >> $GITHUB_ENV - - if: ${{ matrix.docker == true && matrix.alpine == true }} + - if: ${{ matrix.docker == true && matrix.alpine == true && github.ref == 'refs/heads/master'}} name: prebuild linux ${{ matrix.arch }} musl run: docker run -v $PWD:/home --platform linux/${{ matrix.arch }} --rm node:20-alpine bin/sh -c 'apk add bash && cd /home && bash -c "/home/script/ci/prebuild-alpine.sh" && rm -rf ffi node_modules' - - if: ${{ matrix.docker == true && matrix.alpine != true }} + - if: ${{ matrix.docker == true && matrix.alpine != true && github.ref == 'refs/heads/master' }} name: prebuild linux ${{ matrix.arch }} run: docker run -v $PWD:/home --platform linux/${{ matrix.arch }} --rm node:20 bin/bash -c 'cd /home && /home/script/ci/prebuild.sh && rm -rf ffi node_modules' - run: sudo chown -R $(id -u):$(id -g) prebuilds - if: ${{ matrix.docker == true }} + if: ${{ matrix.docker == true && github.ref == 'refs/heads/master' }} - run: ./script/ci/prebuild.sh - if: ${{ matrix.docker != true }} + if: ${{ matrix.docker != true && github.ref == 'refs/heads/master'}} - name: Upload prebuild for ${{ runner.os }}-${{ runner.arch }} uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4 + if: github.ref == 'refs/heads/master' with: path: prebuilds/*.tar.gz name: artifact-${{ matrix.docker == true && matrix.alpine == true && 'linux-musl' || matrix.docker == true && matrix.alpine == false && 'linux' || matrix.os }}-${{ matrix.arch }} @@ -156,7 +159,12 @@ jobs: fetch-depth: 0 - name: Download prebuilds + if: github.ref == 'refs/heads/master' uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + - run: FETCH_ASSETS=true REPO=pact-foundation/pact-js-core ./script/ci/check-release-libs.sh --fetch-assets + if: github.ref != 'refs/heads/master' + env: + GITHUB_TOKEN: ${{ github.token }} - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4 @@ -173,11 +181,11 @@ jobs: - if: ${{ matrix.docker == true && matrix.alpine == true && matrix.arch == 'amd64' && matrix.os == 'ubuntu-latest' }} name: test linux amd64 musl - run: docker run -v $PWD:/home --platform linux/${{ matrix.arch }} --rm node:${{ matrix.node-version }}-alpine bin/sh -c 'apk add bash curl gcompat file && cd /home && /home/script/ci/unpack-and-test.sh' + run: docker run -v $PWD:/home --platform linux/${{ matrix.arch }} --rm node:${{ matrix.node-version }}-alpine bin/sh -c 'apk add jq gettext-envsubst bash curl gcompat file && cd /home && /home/script/ci/unpack-and-test.sh' - if: ${{ matrix.docker == true && matrix.alpine == true && matrix.arch == 'arm64' && matrix.os == 'ubuntu-24.04-arm' }} name: test linux arm64 musl - run: docker run -v $PWD:/home --platform linux/${{ matrix.arch }} --rm node:${{ matrix.node-version }}-alpine bin/sh -c 'apk add bash curl file protoc protobuf-dev && cd /home && /home/script/ci/unpack-and-test.sh' + run: docker run -v $PWD:/home --platform linux/${{ matrix.arch }} --rm node:${{ matrix.node-version }}-alpine bin/sh -c 'apk add jq gettext-envsubst bash curl file protoc protobuf-dev && cd /home && /home/script/ci/unpack-and-test.sh' release_dry_run: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index b428edab..5eebbcc5 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,6 @@ reports tmp .tmp test/__testoutput__ + +# platform-arch specific packages +@pact-foundation/* \ No newline at end of file diff --git a/.npmignore b/.npmignore index aa54c8e6..3681bf5c 100644 --- a/.npmignore +++ b/.npmignore @@ -84,10 +84,16 @@ script binding.gyp native -.cirrus .gitattributes DEVELOPER.md RELEASING.md test.js tsconfig.build.json -tsconfig.json \ No newline at end of file +tsconfig.json + +# Standalone Binaries - Published as seperate packages +@pact-foundation/ + +# Cross packaging files +Makefile +package.json.tmpl \ No newline at end of file diff --git a/DEVELOPER.md b/DEVELOPER.md index 4a90971f..7089ae33 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -4,13 +4,23 @@ Pact-Js-Core uses FFI bindings from the pact-reference project, which are prebui Do this and you should be 👌👌👌: -``` +```sh bash script/ci/prebuild.sh -npm ci --ignore-scripts +supported_platforms=$(./script/ci/build-opt-dependencies.sh determine_platform) +./script/ci/build-opt-dependencies.sh build +./script/ci/build-opt-dependencies.sh link npm run build -npm test +npm run test ``` +set supported platform to one of these values + +- `linux-x64` +- `linux-arm64` +- `darwin-x64` +- `darwin-arm64` +- `windows-x64` + _notes_ - As a developer, you need to run `bash script/ci/prebuild.sh` to @@ -32,61 +42,103 @@ Alternatively you can run the following, which will not create a prebuild, but i bash script/download-libs.sh npm ci npm run build -npm test +npm run test ``` -### Linux x86_64 Task +## Creating Platform specific packages -#### Pre Reqs +We create cross-platform and architecture binaries which are published individually to NPM, and consumed in this project. -1. x86_64 Machine - 1. ARM64 Mac - If you have Rosetta (MacOS) +### Download prebuilt binaries for all platforms -### CI Locally +```sh +./script/ci/build_opt_dependencies.sh libs v15.2.1 +``` -1. Docker/Podman -2. Act +Tag is optional and defaults to latest + +This will run the following script, which will grab the latest prebuilt binaries from GitHub. ```sh -act --container-architecture linux/amd64 -W .github/workflows/build-and-test.yml --artifact-server-path tmp +FETCH_ASSETS=true ./script/ci/check-release-libs.sh --fetch-assets -t v15.2.1 ``` -### MacOS ARM64 Task +### Building all platform specific npm packages -#### Pre Reqs +```sh +./script/ci/build_opt_dependencies.sh build +``` + +### Building individual platform specific npm package -1. Arm64 Mac -2. Cirrus-Cli -3. Tart.run +Supported platforms are +- linux-x64-glibc +- linux-arm64-glibc +- linux-x64-musl +- linux-arm64-musl +- darwin-x64 +- darwin-arm64 +- windows-x64 + +You can detect your platform with ```sh -cirrus run --output github-actions macos_arm --artifacts-dir tmp +./script/ci/build-opt-dependencies.sh determine_platform ``` -### Linux ARM64 Task +You can build with one -#### Pre Reqs +```sh +supported_platforms=$(./script/ci/build-opt-dependencies.sh determine_platform) ./script/ci/build-opt-dependencies.sh build +``` -1. Arm64 Machine +or all -### CI Locally +```sh +./script/ci/build-opt-dependencies.sh build +``` -1. Arm64 Machine -2. Docker / Podman -3. Cirrus-Cli +### Linking arch specific package, for your local build +Make link will try to link all available packages, for all available platforms, and will link any that apply ```sh -cirrus run --output github-actions linux_arm --artifacts-dir tmp +./script/ci/build-opt-dependencies.sh ``` -#### Publishing Assets +You can scope it with `supported_platforms` + +```sh +supported_platforms=$(./script/ci/build-opt-dependencies.sh determine_platform) ./script/ci/build-opt-dependencies.sh link +``` -MacOS ARM64 +### Publishing packages -`cirrus run --output github-actions macos_arm --artifacts-dir tmp --environment GITHUB_TOKEN=$GITHUB_TOKEN --environment CIRRUS_RELEASE=test --environment CIRRUS_REPO_FULL_NAME=pact-foundation/pact-js-core;` +Dry run publishing optional packages, (default) + +```sh +./script/ci/build-opt-dependencies.sh publish +``` -Linux ARM64 +Publishing packages with `--dry-run` option removed. -`cirrus run --output github-actions linux_arm --artifacts-dir tmp --environment GITHUB_TOKEN=$GITHUB_TOKEN --environment CIRRUS_RELEASE=test --environment CIRRUS_REPO_FULL_NAME=pact-foundation/pact-js-core;` \ No newline at end of file +```sh +PUBLISH=true ./script/ci/build-opt-dependencies.sh publish +``` + +### Linux x86_64 Task + +#### Pre Reqs + +1. x86_64 Machine + 1. ARM64 Mac - If you have Rosetta (MacOS) + +### CI Locally + +1. Docker/Podman +2. Act + +```sh +act --container-architecture linux/amd64 -W .github/workflows/build-and-test.yml --artifact-server-path tmp +``` diff --git a/package.json b/package.json index 2c7d657c..05d5bd75 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,18 @@ "publishConfig": { "access": "public" }, + "optionalDependencies": { + "@pact-foundation/pact-core-darwin-arm64": "15.2.1", + "@pact-foundation/pact-core-darwin-x64": "15.2.1", + "@pact-foundation/pact-core-linux-arm64-glibc": "15.2.1", + "@pact-foundation/pact-core-linux-arm64-musl": "15.2.1", + "@pact-foundation/pact-core-linux-x64-glibc": "15.2.1", + "@pact-foundation/pact-core-linux-x64-musl": "15.2.1", + "@pact-foundation/pact-core-windows-x64": "15.2.1" + }, "dependencies": { "check-types": "7.4.0", + "detect-libc": "^2.0.3", "node-gyp-build": "^4.6.0", "pino": "^8.7.0", "pino-pretty": "^9.1.1", diff --git a/package.json.tmpl b/package.json.tmpl new file mode 100644 index 00000000..c3ad4b27 --- /dev/null +++ b/package.json.tmpl @@ -0,0 +1,20 @@ +{ + "name": "${node_pkg}", + "version": "${pkg_version}", + "description": "Platform/arch specific libpact_ffi binaries for @pact-foundation/pact-core", + "license": "MIT", + "repository": { + "type": "git", + "url": "git://github.com/pact-foundation/pact-js-core.git" + }, + "scripts": {}, + "author": "Yousaf Nabi ", + "homepage": "https://github.com/pact-foundation/pact-js-core#readme", + "os": [ + "${node_pkg_os}" + ], + ${libc} + "cpu": [ + "${node_arch}" + ] +} diff --git a/script/ci/build-and-test.sh b/script/ci/build-and-test.sh index abc3c01b..69d21d94 100755 --- a/script/ci/build-and-test.sh +++ b/script/ci/build-and-test.sh @@ -19,11 +19,15 @@ fi node --version npm --version +# Update main package.json optional dependencies versions, with those created earlier +current_platform=$("$SCRIPT_DIR"/build-opt-dependencies.sh determine_platform) +supported_platforms="$current_platform" "$SCRIPT_DIR"/build-opt-dependencies.sh update +# update lockfile post building updated opt deps +npm ci --ignore-scripts || npm i --ignore-scripts +# Link os/arch specific npm package, for running os/arch system -npm ci --ignore-scripts - +supported_platforms="$current_platform" "$SCRIPT_DIR"/build-opt-dependencies.sh link npm run format:check npm run lint npm run build -npm run test -ls -1 \ No newline at end of file +npm run test \ No newline at end of file diff --git a/script/ci/build-opt-dependencies.sh b/script/ci/build-opt-dependencies.sh new file mode 100755 index 00000000..883ee3a7 --- /dev/null +++ b/script/ci/build-opt-dependencies.sh @@ -0,0 +1,178 @@ +#!/bin/bash + +export bin=@pact-foundation/pact-core +export pkg_version=${pkg_version:-$(cat package.json | jq -r .version)} + +if [ -z "${supported_platforms+x}" ]; then + supported_platforms=("linux-x64-glibc" "linux-arm64-glibc" "linux-x64-musl" "linux-arm64-musl" "darwin-x64" "darwin-arm64" "windows-x64") +fi + +setup_package_vars(){ + unset node_os + unset node_arch + unset node_libc + unset libc + IFS='-' read -r node_os node_arch node_libc <<< "$supported_platform" + export node_os=$node_os + export node_pkg_os=$node_os + export node_arch=$node_arch + export node_libc=$node_libc + export prebuild_package="$node_os-$node_arch" + # we need to overwrite windows as win32 in the package.json + if [ "$node_os" = "windows" ]; then + export node_pkg_os=win32 + export prebuild_package="win32-$node_arch" + fi + if [ "$node_libc" = "glibc" ]; then + export libc='"libc": ["glibc"],' + fi + if [ "$node_libc" = "musl" ]; then + export libc='"libc": ["musl"],' + fi + export standalone_package=prebuilds/$prebuild_package + if [ "$node_libc" = "musl" ] || [ "$node_libc" = "glibc" ]; then + export node_pkg=${bin}-$node_os-$node_arch-$node_libc + else + export node_pkg=${bin}-$node_os-$node_arch + fi +} + +clean() { + rm -rf @pact-foundation + npm run clean-libs +} + +libs() { + echo $1 + if [ -n "$1" ]; then + tag=$1 + else + tag=v${pkg_version} + fi + FETCH_ASSETS=true ./script/ci/check-release-libs.sh --fetch-assets -t $tag +} + +build() { + for supported_platform in "${supported_platforms[@]}"; do + setup_package_vars + echo "Building for $node_os-$node_arch" + echo "Building $node_pkg" + echo "Build $node_libc" + mkdir -p "$node_pkg/prebuilds" + cp -R "$standalone_package" "$node_pkg/prebuilds" + if [ "$node_libc" = "glibc" ]; then + find "$node_pkg/prebuilds" -type f -name '*musl*' -exec rm -f {} + + fi + if [ "$node_libc" = "musl" ]; then + find "$node_pkg/prebuilds" -type f ! -name '*musl*' -exec rm -f {} + + fi + envsubst < package.json.tmpl > "$node_pkg/package.json" + if [ "${PUBLISH:-false}" = true ]; then + (cd $node_pkg && npm publish --access public) + else + (cd $node_pkg && npm publish --access public --dry-run) + fi + done +} + +update() { + for supported_platform in "${supported_platforms[@]}"; do + setup_package_vars + jq '.optionalDependencies."'$node_pkg'" = "'$pkg_version'"' package.json > package-new.json + mv package-new.json package.json + done +} + +publish() { + set -eu + for supported_platform in "${supported_platforms[@]}"; do + setup_package_vars + echo "Building for $node_os-$node_arch" + echo "Building $node_pkg for $node_os-$node_arch" + if [ "${PUBLISH:-false}" = true ]; then + (cd $node_pkg && npm publish --access public) + else + (cd $node_pkg && npm publish --access public --dry-run) + fi + done +} + +link() { + set -eu + for supported_platform in "${supported_platforms[@]}"; do + setup_package_vars + (cd $node_pkg && npm link || echo "cannot link for platform") + npm link $node_pkg || echo "cannot link for platform" + done +} + +determine_platform(){ + case "$(uname -s)" in + Linux) + if [ "$(uname -m)" == "x86_64" ]; then + if [ -f /etc/os-release ] && grep -q 'Alpine' /etc/os-release; then + current_platform="linux-x64-musl" + else + current_platform="linux-x64-glibc" + fi + elif [ "$(uname -m)" == "aarch64" ]; then + if [ -f /etc/os-release ] && grep -q 'Alpine' /etc/os-release; then + current_platform="linux-arm64-musl" + else + export current_platform="linux-arm64-glibc" + fi + fi + ;; + Darwin) + if [ "$(uname -m)" == "x86_64" ]; then + export current_platform="darwin-x64" + elif [ "$(uname -m)" == "arm64" ]; then + export current_platform="darwin-arm64" + fi + ;; + CYGWIN*|MINGW32*|MSYS*|MINGW*) + export current_platform="windows-x64" + ;; + *) + echo "Unsupported platform: $(uname -s)" + exit 1 + ;; + esac + if [ -z "$current_platform" ]; then + echo "Error: could not determine current_platform" + exit 1 + fi + echo $current_platform +} + +help() { + echo "Pact platform/arch specific dependency builder" + + echo "Usage: $0 {clean|libs|build_opt_deps|update_opt_deps|publish_opt_package|link|determine_platform|help}" + echo + echo "Functions:" + echo " clean - Clean the build environment" + echo " libs - Fetch and check release libraries" + echo " build_opt_deps - Build optional dependencies for supported platforms" + echo " update_opt_deps - Update optional dependencies in package.json" + echo " publish_opt_package - Publish the optional package" + echo " link - Link the package for development" + echo " determine_platform - Determine the current platform" + echo " help - Display this help message" + + echo + echo "Supported platforms:" + for platform in "${supported_platforms[@]}"; do + echo " - $platform" + done + echo + echo "Example to run for the current platform:" + echo ' supported_platforms=$(./script/ci/build_opt_dependencies.sh determine_platform) ./script/ci/build_opt_dependencies.sh link' +} + +if [ $# -eq 0 ]; then + help + exit 1 +fi + +"$@" \ No newline at end of file diff --git a/script/ci/check-release-libs.sh b/script/ci/check-release-libs.sh index e8b64007..c03eb38e 100755 --- a/script/ci/check-release-libs.sh +++ b/script/ci/check-release-libs.sh @@ -69,7 +69,7 @@ if [[ "$TAG" == "" ]]; then else GH_TAG_OPTION="$TAG" if [[ "$TAG" == "latest" ]]; then - GH_TAG_OPTION='' + GH_TAG_OPTION=$(gh release list --limit 1 --repo pact-foundation/pact-js-core --json tagName --jq '.[].tagName') fi if [[ "${LIST_ASSETS:-}" = true || "${FETCH_ASSETS:-}" = true ]]; then diff --git a/script/ci/lib/publish.sh b/script/ci/lib/publish.sh index 0020219a..8f812d07 100755 --- a/script/ci/lib/publish.sh +++ b/script/ci/lib/publish.sh @@ -6,20 +6,23 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)" # Figure out where the require_binary npm -VERSION="$("$SCRIPT_DIR/get-version.sh")" - +# VERSION="$("$SCRIPT_DIR/get-version.sh")" echo "--> Releasing version ${VERSION}" echo "--> Releasing artifacts" echo " Publishing pact-core@${VERSION}..." if [[ ${DRY_RUN:-} == 'true' ]]; then echo "publishing in dry run mode" + # Dry-run Publish os/arch specific npm packages + "$SCRIPT_DIR"/../build-opt-dependencies.sh publish npm publish --access-public --dry-run else echo "--> Preparing npmrc file" "$SCRIPT_DIR"/create_npmrc_file.sh echo "--> Removing binding.gyp to prevent rebuild. See https://github.com/npm/cli/issues/5234#issuecomment-1291139150" rm "${SCRIPT_DIR}/../../../binding.gyp" + # Publish os/arch specific npm packages + PUBLISH=true "$SCRIPT_DIR"/../build-opt-dependencies.sh publish npm publish --access public --tag latest fi echo " done!" diff --git a/script/ci/prebuild-alpine.sh b/script/ci/prebuild-alpine.sh index 83cad069..59127258 100755 --- a/script/ci/prebuild-alpine.sh +++ b/script/ci/prebuild-alpine.sh @@ -12,7 +12,7 @@ apk add bash curl python3 make g++ . "${SCRIPT_DIR}/../lib/export-binary-versions.sh" "${SCRIPT_DIR}/../lib/download-ffi.sh" rm -rf build node_modules -npm ci --ignore-scripts +npm ci --ignore-scripts || npm i --ignore-scripts export npm_config_target=${NODE_VERSION} npx --yes prebuildify@${PREBUILDIFY_VERSION} --napi --libc musl --strip --tag-libc --name ${PREBUILD_NAME} diff --git a/script/ci/prebuild.sh b/script/ci/prebuild.sh index c3c5b0a3..afd356dd 100755 --- a/script/ci/prebuild.sh +++ b/script/ci/prebuild.sh @@ -1,4 +1,4 @@ -# !/bin/bash -eu +#!/bin/bash -eu set -e # This needs to be here for windows bash, which doesn't read the #! line above set -u @@ -35,7 +35,7 @@ echo "OS: $OS" echo "ARCH: $ARCH" ./script/download-libs.sh -npm ci --ignore-scripts +npm ci --ignore-scripts || npm i --ignore-scripts export npm_config_target=${NODE_VERSION} npx --yes prebuildify@${PREBUILDIFY_VERSION} --napi --name ${PREBUILD_NAME} ls prebuilds/**/* diff --git a/script/ci/release.sh b/script/ci/release.sh index 113d9d42..9a1869f0 100755 --- a/script/ci/release.sh +++ b/script/ci/release.sh @@ -47,17 +47,7 @@ if [ "${GH_CREATE_PRE_RELEASE:-}" = true ]; then echo "echo shouldnt get here" exit 0 elif [ "${GH_PRE_RELEASE_UPLOAD:-}" = true ]; then - echo "Uploading pre-release ${NEXT_TAG}" - echo "get latest Draft pre-release" - if [[ ${CIRRUS_CI:-} == 'true' && ${CIRRUS_BRANCH:-} != 'master' ]]; then - echo "Not on master in CIRRUS_CI, skipping pre-release upload" - exit 0 - fi - if [[ ${CIRRUS_CI:-} == 'true' ]]; then - LATEST_DRAFT_PRERELEASE=$(gh release list --limit 1 --repo $REPO | grep Draft | awk '{print $2}') - NEXT_TAG=${LATEST_DRAFT_PRERELEASE} - fi gh release upload ${NEXT_TAG} prebuilds/*.tar.gz --repo ${REPO} --clobber exit 0 fi @@ -80,6 +70,9 @@ fi FETCH_ASSETS=true ./script/ci/check-release-libs.sh --fetch-assets -t "${NEXT_TAG}" "$SCRIPT_DIR"/../download-plugins.sh +export pkg_version=$NEXT_VERSION +"$SCRIPT_DIR"/build-opt-dependencies.sh build +"$SCRIPT_DIR"/build-opt-dependencies.sh update "$SCRIPT_DIR"/build-and-test.sh if [[ ${DRY_RUN:-} == 'true' ]]; then @@ -98,7 +91,11 @@ else VERSION="$("$SCRIPT_DIR/lib/get-version.sh")" TAG="v${VERSION}" fi - +export VERSION +set +eu +# GITHUB_OUPUT is unset if testing DRY_RUN locally +echo "VERSION=$VERSION" >> $GITHUB_OUTPUT +set -eu "$SCRIPT_DIR"/lib/publish.sh # Push the new commit back to the repo. diff --git a/script/ci/unpack-and-test.sh b/script/ci/unpack-and-test.sh index 82671286..7002ef6b 100755 --- a/script/ci/unpack-and-test.sh +++ b/script/ci/unpack-and-test.sh @@ -5,9 +5,16 @@ set -u SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)" # Figure out where the script is running . "$SCRIPT_DIR"/../lib/robust-bash.sh -ls -1 -mkdir -p prebuilds -mv artifact*/*.tar.gz . -ls *.gz |xargs -n1 tar -xzf +if [ ! -d "prebuilds" ]; then + ls -1 + ls -1 artifact* + mkdir -p prebuilds + mv artifact*/*.tar.gz . + ls *.gz | xargs -n1 tar -xzf +fi + "$SCRIPT_DIR"/../download-plugins.sh +# Use the determined platform +current_platform=$("$SCRIPT_DIR"/build-opt-dependencies.sh determine_platform) +supported_platforms="$current_platform" "$SCRIPT_DIR"/build-opt-dependencies.sh build "$SCRIPT_DIR"/build-and-test.sh \ No newline at end of file diff --git a/src/ffi/index.ts b/src/ffi/index.ts index 9b486cac..ebf87100 100644 --- a/src/ffi/index.ts +++ b/src/ffi/index.ts @@ -1,11 +1,50 @@ import path from 'node:path'; import bindings = require('node-gyp-build'); +import { isNonGlibcLinuxSync } from 'detect-libc'; import logger, { DEFAULT_LOG_LEVEL } from '../logger'; import { LogLevel } from '../logger/types'; import { Ffi, FfiLogLevelFilter } from './types'; export const PACT_FFI_VERSION = '0.4.22'; +/** + * Returns the library path which is located inside `node_modules` + * The naming convention is @pact-foundation/pact-core-${os}-${arch}<-${libc}> + * - "-${libc}" is optional for linux only + * @see https://nodejs.org/api/os.html#osarch + * @see https://nodejs.org/api/os.html#osplatform + * @example "x/xx/node_modules/@pact-foundation/pact-core-darwin-arm64" + */ +function getPlatformArchSpecificPackage() { + const { arch } = process; + let os = process.platform as string; + if (['win32', 'cygwin'].includes(process.platform)) { + os = 'windows'; + } + let platformArchSpecificPackage = `@pact-foundation/pact-core-${os}-${arch}`; + if (os === 'linux') { + platformArchSpecificPackage += isNonGlibcLinuxSync() ? '-musl' : '-glibc'; + } + + const prebuildPackageLocation = process.env['PACT_PREBUILD_PACKAGE_LOCATION']; + if (prebuildPackageLocation) { + platformArchSpecificPackage = path.join( + prebuildPackageLocation, + platformArchSpecificPackage + ); + } + + const packagePath = `${platformArchSpecificPackage}/package.json`; + try { + require.resolve(packagePath); + return platformArchSpecificPackage; + } catch (e) { + throw new Error( + `Couldn't find npm package ${platformArchSpecificPackage} \n 💡 you can tell Pact where the npm package is located with env var $PACT_PREBUILD_PACKAGE_LOCATION` + ); + } +} + // supported prebuilds // darwin-arm64 // darwin-x64 @@ -54,6 +93,13 @@ const bindingsResolver = (bindingsPath: string | undefined) => bindings(bindingsPath); const bindingPaths = [ + path.resolve( + __dirname, + '..', + '..', + 'node_modules', + getPlatformArchSpecificPackage() + ), path.resolve(__dirname, '..', '..'), process.env['PACT_PREBUILD_LOCATION']?.toString() ?? path.resolve(), ];