Skip to content

Commit

Permalink
chore: vendor node-gyp-build
Browse files Browse the repository at this point in the history
  • Loading branch information
YOU54F committed Mar 13, 2024
1 parent 7ff9ad6 commit 46789af
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 3 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
"cross-spawn": "7.0.3",
"mkdirp": "1.0.0",
"needle": "^3.2.0",
"node-gyp-build": "^4.6.0",
"pino": "^8.7.0",
"pino-pretty": "^9.1.1",
"promise-timeout": "1.3.0",
Expand Down
4 changes: 3 additions & 1 deletion src/ffi/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import path from 'node:path';
import bindings = require('node-gyp-build');
import logger, { DEFAULT_LOG_LEVEL } from '../logger';
import { LogLevel } from '../logger/types';
import { Ffi } from './types';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const bindings = require('./node-gyp-build/index');

export const PACT_FFI_VERSION = '0.4.16';

// supported prebuilds
Expand Down
1 change: 0 additions & 1 deletion src/ffi/node-gyp-build.ts

This file was deleted.

21 changes: 21 additions & 0 deletions src/ffi/node-gyp-build/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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.
12 changes: 12 additions & 0 deletions src/ffi/node-gyp-build/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (typeof process.addon === 'function') {
// if the platform supports native resolving prefer that
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
module.exports = process.addon.bind(process);
} else {
// else use the runtime version here
// eslint-disable-next-line global-require, import/extensions
module.exports = require('./node-gyp-build.js');
}
285 changes: 285 additions & 0 deletions src/ffi/node-gyp-build/node-gyp-build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs');
const path = require('path');
const os = require('os');

const runtimeRequire =
// Workaround to fix webpack's build warnings: 'the request of a dependency is an expression'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require; // eslint-disable-line
function readdirSync(dir: string | undefined) {
try {
return fs.readdirSync(dir);
} catch (err) {
return [];
}
}

function getFirst(
dir: string | undefined,
filter: { (name: unknown): boolean; (name: unknown): boolean }
) {
const files = readdirSync(dir).filter(filter);
return files[0] && path.join(dir, files[0]);
}

function matchBuild(name: string) {
return /\.node$/.test(name);
}

function parseTuple(name: string) {
// Example: darwin-x64+arm64
const arr = name.split('-');
if (arr.length !== 2) return;

const platform = arr[0];
const architectures = arr[1].split('+');

if (!platform) return;
if (!architectures.length) return;
if (!architectures.every(Boolean)) return;

// eslint-disable-next-line consistent-return
return { name, platform, architectures };
}

function matchTuple(platform: string, arch: string) {
return function (

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, ubuntu-latest)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, ubuntu-latest)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, ubuntu-latest)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, windows-latest)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, macos-14)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, windows-latest)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, windows-latest)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, macos-12)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, macos-14)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, macos-14)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, macos-12)

Unexpected unnamed function

Check warning on line 49 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, macos-12)

Unexpected unnamed function
tuple: { platform: string; architectures: string | string[] } | null
) {
if (tuple == null) return false;
if (tuple.platform !== platform) return false;
return tuple.architectures.includes(arch);
};
}

function compareTuples(
a: { architectures: string | string[] },
b: { architectures: string | string[] }
) {
// Prefer single-arch prebuilds over multi-arch
return a.architectures.length - b.architectures.length;
}

function parseTags(file: string) {
const arr = file.split('.');
const extension = arr.pop();
const tags = { file, specificity: 0 };

if (extension !== 'node') return;

// eslint-disable-next-line no-plusplus
for (let i = 0; i < arr.length; i++) {
const tag = arr[i];

if (tag === 'node' || tag === 'electron' || tag === 'node-webkit') {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
tags.runtime = tag;
} else if (tag === 'napi') {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
tags.napi = true;
} else if (tag.slice(0, 3) === 'abi') {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
tags.abi = tag.slice(3);
} else if (tag.slice(0, 2) === 'uv') {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
tags.uv = tag.slice(2);
} else if (tag.slice(0, 4) === 'armv') {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
tags.armv = tag.slice(4);
} else if (tag === 'glibc' || tag === 'musl') {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
tags.libc = tag;
} else {
// eslint-disable-next-line no-continue
continue;
}

// eslint-disable-next-line no-plusplus
tags.specificity++;
}

// eslint-disable-next-line consistent-return
return tags;
}

function runtimeAgnostic(tags: { runtime: string; napi: string }) {
return tags.runtime === 'node' && tags.napi;
}
function matchTags(runtime: string, abi: string) {
return function (

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, ubuntu-latest)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, ubuntu-latest)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, ubuntu-latest)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, windows-latest)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, macos-14)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, windows-latest)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, windows-latest)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, macos-12)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, macos-14)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, macos-14)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, macos-12)

Unexpected unnamed function

Check warning on line 118 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, macos-12)

Unexpected unnamed function
tags: {
runtime: string;
abi: string;
napi: string;
uv: string;
armv: string;
libc: string;
} | null
) {
if (tags == null) return false;
if (tags.runtime !== runtime && !runtimeAgnostic(tags)) return false;
if (tags.abi !== abi && !tags.napi) return false;
// eslint-disable-next-line @typescript-eslint/no-use-before-define
if (tags.uv && tags.uv !== uv) return false;
if (tags.armv && tags.armv !== armv) return false;
if (tags.libc && tags.libc !== libc) return false;

return true;
};
}

function compareTags(runtime: string) {
// Precedence: non-agnostic runtime, abi over napi, then by specificity.

return function (

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, ubuntu-latest)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, ubuntu-latest)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, ubuntu-latest)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, windows-latest)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, macos-14)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, windows-latest)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, windows-latest)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, macos-12)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, macos-14)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, macos-14)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, macos-12)

Unexpected unnamed function

Check warning on line 143 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, macos-12)

Unexpected unnamed function
a: { runtime: string; abi: string; specificity: number },
b: { runtime: string; abi: string; specificity: number }
) {
if (a.runtime !== b.runtime) {
return a.runtime === runtime ? -1 : 1;
}
if (a.abi !== b.abi) {
return a.abi ? -1 : 1;
}
if (a.specificity !== b.specificity) {
return a.specificity > b.specificity ? -1 : 1;
}
return 0;
};
}

function isNwjs() {
return !!(process.versions && process.versions['nw']);
}

function isElectron() {
if (process.versions && process.versions['electron']) return true;
if (process.env['ELECTRON_RUN_AS_NODE']) return true;

return (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
typeof window !== 'undefined' &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.process &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.process.type === 'renderer'
);
}

function isAlpine(platform: string) {
return platform === 'linux' && fs.existsSync('/etc/alpine-release');
}
const vars = (process.config && process.config.variables) || {};
const prebuildsOnly = !!process.env['PREBUILDS_ONLY'];
const abi = process.versions.modules; // TODO: support old node where this is undef
// eslint-disable-next-line no-nested-ternary
const runtime = isElectron() ? 'electron' : isNwjs() ? 'node-webkit' : 'node';

const arch = process.env['npm_config_arch'] || os.arch();
const platform = process.env['npm_config_platform'] || os.platform();
const libc = process.env['LIBC'] || (isAlpine(platform) ? 'musl' : 'glibc');
const armv =
process.env['ARM_VERSION'] ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
(arch === 'arm64' ? '8' : vars.arm_version) ||
'';
const uv = (process.versions.uv || '').split('.')[0];
function load(dir: string | undefined) {
return runtimeRequire(load.resolve(dir));
}

// eslint-disable-next-line no-multi-assign
load.resolve = load.path = function (dir: string | undefined) {

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, ubuntu-latest)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, ubuntu-latest)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, ubuntu-latest)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, windows-latest)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, macos-14)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, windows-latest)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, windows-latest)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (16, macos-12)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, macos-14)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, macos-14)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (18, macos-12)

Unexpected unnamed function

Check warning on line 205 in src/ffi/node-gyp-build/node-gyp-build.ts

View workflow job for this annotation

GitHub Actions / test (20, macos-12)

Unexpected unnamed function
// eslint-disable-next-line no-param-reassign
dir = path.resolve(dir || '.');

try {
const name = runtimeRequire(path.join(dir, 'package.json'))
.name.toUpperCase()
.replace(/-/g, '_');
// eslint-disable-next-line no-param-reassign
if (process.env[`${name}_PREBUILD`]) dir = process.env[`${name}_PREBUILD`];
} catch (err) {
/* empty */
}

if (!prebuildsOnly) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const release = getFirst(path.join(dir, 'build/Release'), matchBuild);
if (release) return release;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const debug = getFirst(path.join(dir, 'build/Debug'), matchBuild);
if (debug) return debug;
}
// eslint-disable-next-line @typescript-eslint/no-shadow
function resolve(dir: string | undefined) {
// Find matching "prebuilds/<platform>-<arch>" directory
const tuples = readdirSync(path.join(dir, 'prebuilds')).map(parseTuple);
const tuple = tuples
.filter(matchTuple(platform, arch))
.sort(compareTuples)[0];
if (!tuple) return;

// Find most specific flavor first
const prebuilds = path.join(dir, 'prebuilds', tuple.name);
const parsed = readdirSync(prebuilds).map(parseTags);
const candidates = parsed.filter(matchTags(runtime, abi));
const winner = candidates.sort(compareTags(runtime))[0];
// eslint-disable-next-line consistent-return
if (winner) return path.join(prebuilds, winner.file);
}
const prebuild = resolve(dir);
if (prebuild) return prebuild;

const nearby = resolve(path.dirname(process.execPath));
if (nearby) return nearby;

const target = [
`platform=${platform}`,
`arch=${arch}`,
`runtime=${runtime}`,
`abi=${abi}`,
`uv=${uv}`,
armv ? `armv=${armv}` : '',
`libc=${libc}`,
`node=${process.versions.node}`,
process.versions['electron']
? `electron=${process.versions['electron']}`
: '',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
typeof __webpack_require__ === 'function' ? 'webpack=true' : '', // eslint-disable-line
]
.filter(Boolean)
.join(' ');

throw new Error(
`No native build was found for ${target}\n loaded from: ${dir}\n`
);
};

module.exports = load;

// Exposed for unit tests
// TODO: move to lib
load.parseTags = parseTags;
load.matchTags = matchTags;
load.compareTags = compareTags;
load.parseTuple = parseTuple;
load.matchTuple = matchTuple;
load.compareTuples = compareTuples;

0 comments on commit 46789af

Please sign in to comment.