Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use autogenerated ABI target list #83

Merged
merged 2 commits into from
Aug 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/update-abi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Auto-update ABI JSON file
on:
schedule:
- cron: '0 0 * * *'
jobs:
autoupdate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Get npm cache directory
id: npm-cache
run: |
echo "::set-output name=dir::$(npm config get cache)"
- uses: actions/cache@v1
with:
path: ${{ steps.npm-cache.outputs.dir }}
key: ${{ runner.os }}-node-${{ hashFiles('**/package.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm install
- name: Update Releases JSON
run: npm run electron-releases
- name: Commit Changes to Releases JSON
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "machine github.com login $GITHUB_ACTOR password $GITHUB_TOKEN" > ~/.netrc
chmod 600 ~/.netrc
git add abi_registry.json
if test -n "$(git status -s)"; then
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
git diff --cached
git commit -m "build: update Electron releases JSON"
git push origin HEAD:$GITHUB_REF
else
echo No update needed
fi
78 changes: 78 additions & 0 deletions abi_registry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
[
{
"runtime": "node",
"target": "11.0.0",
"lts": false,
"future": false,
"abi": "67"
},
{
"runtime": "electron",
"target": "5.0.0",
"lts": false,
"future": false,
"abi": "70"
},
{
"runtime": "node",
"target": "12.0.0",
"lts": [
"2019-10-21",
"2020-10-20"
],
"future": false,
"abi": "68"
},
{
"runtime": "electron",
"target": "6.0.0",
"lts": false,
"future": false,
"abi": "73"
},
{
"runtime": "electron",
"target": "7.0.0",
"lts": false,
"future": false,
"abi": "75"
},
{
"runtime": "electron",
"target": "8.0.0",
"lts": false,
"future": false,
"abi": "76"
},
{
"runtime": "node",
"target": "13.0.0",
"lts": false,
"future": false,
"abi": "74"
},
{
"runtime": "electron",
"target": "9.0.0-beta.1",
"lts": false,
"future": true,
"abi": "80"
},
{
"runtime": "node",
"target": "14.0.0",
"lts": [
"2020-10-20",
"2021-10-19"
],
"future": true,
"abi": "81"
},
{
"runtime": "electron",
"target": "10.0.0-beta.1",
"lts": false,
"future": true,
"abi": "82"
}
]
60 changes: 47 additions & 13 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,54 @@ function getTarget (abi, runtime) {
throw new Error('Could not detect target for abi ' + abi + ' and runtime ' + runtime)
}

function loadGeneratedTargets () {
var registry = require('./abi_registry.json')
var targets = {
supported: [],
additional: [],
future: []
}

registry.forEach(function (item) {
var target = {
runtime: item.runtime,
target: item.target,
abi: item.abi
}
if (item.lts) {
var startDate = new Date(Date.parse(item.lts[0]))
var endDate = new Date(Date.parse(item.lts[1]))
var currentDate = new Date()
target.lts = startDate < currentDate && currentDate < endDate
} else {
target.lts = false
}

if (target.runtime === 'node-webkit') {
targets.additional.push(target)
} else if (item.future) {
targets.future.push(target)
} else {
targets.supported.push(target)
}
})

targets.supported.sort()
targets.additional.sort()
targets.future.sort()

return targets
}

var generatedTargets = loadGeneratedTargets()

var supportedTargets = [
{runtime: 'node', target: '5.0.0', abi: '47', lts: false},
{runtime: 'node', target: '6.0.0', abi: '48', lts: false},
{runtime: 'node', target: '7.0.0', abi: '51', lts: false},
{runtime: 'node', target: '8.0.0', abi: '57', lts: false},
{runtime: 'node', target: '9.0.0', abi: '59', lts: false},
{runtime: 'node', target: '10.0.0', abi: '64', lts: new Date(2018, 10, 1) < new Date() && new Date() < new Date(2020, 4, 31)},
{runtime: 'node', target: '11.0.0', abi: '67', lts: false},
{runtime: 'node', target: '12.0.0', abi: '72', lts: new Date(2019, 9, 21) < new Date() && new Date() < new Date(2020, 9, 31)},
{runtime: 'node', target: '13.0.0', abi: '79', lts: false},
{runtime: 'node', target: '14.0.0', abi: '83', lts: false},
{runtime: 'electron', target: '0.36.0', abi: '47', lts: false},
{runtime: 'electron', target: '1.1.0', abi: '48', lts: false},
{runtime: 'electron', target: '1.3.0', abi: '49', lts: false},
Expand All @@ -70,14 +107,11 @@ var supportedTargets = [
{runtime: 'electron', target: '2.0.0', abi: '57', lts: false},
{runtime: 'electron', target: '3.0.0', abi: '64', lts: false},
{runtime: 'electron', target: '4.0.0', abi: '64', lts: false},
{runtime: 'electron', target: '4.0.4', abi: '69', lts: false},
{runtime: 'electron', target: '5.0.0', abi: '70', lts: false},
{runtime: 'electron', target: '6.0.0', abi: '73', lts: false},
{runtime: 'electron', target: '7.0.0', abi: '75', lts: false},
{runtime: 'electron', target: '8.0.0', abi: '76', lts: false},
{runtime: 'electron', target: '9.0.0', abi: '80', lts: false}
{runtime: 'electron', target: '4.0.4', abi: '69', lts: false}
]

supportedTargets.push.apply(supportedTargets, generatedTargets.supported)

var additionalTargets = [
{runtime: 'node-webkit', target: '0.13.0', abi: '47', lts: false},
{runtime: 'node-webkit', target: '0.15.0', abi: '48', lts: false},
Expand All @@ -86,6 +120,8 @@ var additionalTargets = [
{runtime: 'node-webkit', target: '0.26.5', abi: '59', lts: false}
]

additionalTargets.push.apply(additionalTargets, generatedTargets.additional)

var deprecatedTargets = [
{runtime: 'node', target: '0.2.0', abi: '1', lts: false},
{runtime: 'node', target: '0.9.1', abi: '0x000A', lts: false},
Expand All @@ -104,9 +140,7 @@ var deprecatedTargets = [
{runtime: 'electron', target: '0.33.0', abi: '46', lts: false}
]

var futureTargets = [
{runtime: 'electron', target: '10.0.0-beta.1', abi: '82', lts: false}
]
var futureTargets = generatedTargets.future

var allTargets = deprecatedTargets
.concat(supportedTargets)
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
"description": "Get the Node ABI for a given target and runtime, and vice versa.",
"main": "index.js",
"scripts": {
"test": "tape test/index.js",
"semantic-release": "semantic-release",
"travis-deploy-once": "travis-deploy-once"
"test": "tape test/index.js",
"travis-deploy-once": "travis-deploy-once",
"update-abi-registry": "node --unhandled-rejections=strict scripts/update-abi-registry.js"
},
"repository": {
"type": "git",
Expand All @@ -26,6 +27,7 @@
},
"homepage": "https://github.com/lgeiger/node-abi#readme",
"devDependencies": {
"got": "^10.6.0",
"semantic-release": "^15.8.0",
"tape": "^4.6.3",
"travis-deploy-once": "^5.0.1"
Expand Down
93 changes: 93 additions & 0 deletions scripts/update-abi-registry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const got = require('got')
const path = require('path')
const semver = require('semver')
const { writeFile } = require('fs').promises

async function getJSONFromCDN (urlPath) {
const response = await got(`https://cdn.jsdelivr.net/gh/${urlPath}`)
return JSON.parse(response.body)
}

async function fetchElectronVersions () {
return (await getJSONFromCDN('electron/releases/lite.json')).map(metadata => metadata.version)
}

async function fetchNodeVersions () {
const schedule = await getJSONFromCDN('nodejs/Release/schedule.json')
const versions = {}

for (const [majorVersion, metadata] of Object.entries(schedule)) {
if (majorVersion.startsWith('v0')) {
continue
}
const version = `${majorVersion.slice(1)}.0.0`
const lts = metadata.hasOwnProperty('lts') ? [metadata.lts, metadata.maintenance] : false
versions[version] = {
runtime: 'node',
target: version,
lts: lts,
future: new Date(Date.parse(metadata.start)) > new Date()
}
}

return versions
}

async function fetchAbiVersions () {
return (await getJSONFromCDN('nodejs/node/doc/abi_version_registry.json')).NODE_MODULE_VERSION
}

async function main () {
const nodeVersions = await fetchNodeVersions()
const abiVersions = await fetchAbiVersions()
const electronVersions = await fetchElectronVersions()

const abiVersionSet = new Set()
const supportedTargets = []
for (const abiVersion of abiVersions) {
if (abiVersion.modules <= 66) {
// Don't try to parse any ABI versions older than 60
break
} else if (abiVersion.runtime === 'electron' && abiVersion.modules < 70) {
// Don't try to parse Electron ABI versions below Electron 5
continue
}

let target
if (abiVersion.runtime === 'node') {
const nodeVersion = `${abiVersion.versions.replace('.0.0-pre', '')}.0.0`
target = nodeVersions[nodeVersion]
if (!target) {
continue
}
} else {
target = {
runtime: abiVersion.runtime === 'nw.js' ? 'node-webkit' : abiVersion.runtime,
target: abiVersion.versions,
lts: false,
future: false
}
if (target.runtime === 'electron') {
target.target = `${target.target}.0.0`
const constraint = /^[0-9]/.test(abiVersion.versions) ? `>= ${abiVersion.versions}` : abiVersion.versions
if (!electronVersions.find(electronVersion => semver.satisfies(electronVersion, constraint))) {
target.target = `${target.target}-beta.1`
target.future = true
}
}
}
target.abi = abiVersion.modules.toString()

const key = [target.runtime, target.target].join('-')
if (abiVersionSet.has(key)) {
continue
}

abiVersionSet.add(key)
supportedTargets.unshift(target)
}

await writeFile(path.resolve(__dirname, '..', 'abi_registry.json'), JSON.stringify(supportedTargets, null, 2))
}

main()
10 changes: 6 additions & 4 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ var getTarget = require('../index').getTarget
var getNextTarget = require('../index')._getNextTarget
var allTargets = require('../index').allTargets

test('getNextTarget gets the next unsopported target', function (t) {
test('getNextTarget gets the next unsupported target', function (t) {
var mockTargets = [
{runtime: 'node', target: '7.0.0', abi: '51', lts: false},
{runtime: 'node', target: '8.0.0', abi: '57', lts: false},
Expand Down Expand Up @@ -35,6 +35,7 @@ test('getTarget calculates correct Electron target', function (t) {
t.equal(getTarget('48', 'electron'), '1.1.0')
t.equal(getTarget('49', 'electron'), '1.3.0')
t.equal(getTarget('50', 'electron'), '1.4.0')
t.equal(getTarget('76', 'electron'), '8.0.0')
t.end()
})

Expand All @@ -53,6 +54,7 @@ test('getAbi calculates correct Node ABI', function (t) {
t.equal(getAbi(null), process.versions.modules)
t.throws(function () { getAbi('a.b.c') })
t.throws(function () { getAbi(getNextTarget('node')) })
t.equal(getAbi('12.0.0'), '68')
t.equal(getAbi('7.2.0'), '51')
t.equal(getAbi('7.0.0'), '51')
t.equal(getAbi('6.9.9'), '48')
Expand Down Expand Up @@ -155,8 +157,8 @@ test('allTargets are sorted', function (t) {
return semver.compare(t1.target, t2.target)
}

t.deepEqual(electron, electron.slice().sort(sort))
t.deepEqual(node, node.slice().sort(sort))
t.deepEqual(nodeWebkit, nodeWebkit.slice().sort(sort))
t.deepEqual(electron, electron.slice().sort(sort), 'electron targets are sorted')
t.deepEqual(node, node.slice().sort(sort), 'node targets are sorted')
t.deepEqual(nodeWebkit, nodeWebkit.slice().sort(sort), 'node-webkit targets are sorted')
t.end()
})