Skip to content

Commit

Permalink
feat: support libc field checks (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
nlf committed Mar 21, 2023
1 parent 1b50fa7 commit 1b6f3e4
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 4 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ Errors have a `required` and `current` fields.

### .checkEngine(pkg, npmVer, nodeVer, force = false)

Check if node/npm version is supported by the package. If it isn't
supported, an error is thrown.
Check if a package's `engines.node` and `engines.npm` match the running system.

`force` argument will override the node version check, but not the npm
version check, as this typically would indicate that the current version of
Expand All @@ -22,6 +21,8 @@ Error code: 'EBADENGINE'

### .checkPlatform(pkg, force)

Check if OS/Arch is supported by the package.
Check if a package's `os`, `cpu` and `libc` match the running system.

`force` argument skips all checks.

Error code: 'EBADPLATFORM'
23 changes: 22 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const checkEngine = (target, npmVer, nodeVer, force = false) => {
}
}

const isMusl = (file) => file.includes('libc.musl-') || file.includes('ld-musl-')

const checkPlatform = (target, force = false) => {
if (force) {
return
Expand All @@ -30,16 +32,35 @@ const checkPlatform = (target, force = false) => {
const osOk = target.os ? checkList(platform, target.os) : true
const cpuOk = target.cpu ? checkList(arch, target.cpu) : true

if (!osOk || !cpuOk) {
let libcOk = true
let libcFamily = null
if (target.libc) {
// libc checks only work in linux, any value is a failure if we aren't
if (platform !== 'linux') {
libcOk = false
} else {
const report = process.report.getReport()
if (report.header?.glibcRuntimeVersion) {
libcFamily = 'glibc'
} else if (Array.isArray(report.sharedObjects) && report.sharedObjects.some(isMusl)) {
libcFamily = 'musl'
}
libcOk = libcFamily ? checkList(libcFamily, target.libc) : false
}
}

if (!osOk || !cpuOk || !libcOk) {
throw Object.assign(new Error('Unsupported platform'), {
pkgid: target._id,
current: {
os: platform,
cpu: arch,
libc: libcFamily,
},
required: {
os: target.os,
cpu: target.cpu,
libc: target.libc,
},
code: 'EBADPLATFORM',
})
Expand Down
78 changes: 78 additions & 0 deletions test/check-platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,81 @@ t.test('os wrong (negation)', async t =>

t.test('nothing wrong (negation)', async t =>
checkPlatform({ cpu: '!enten-cpu', os: '!enten-os' }))

t.test('libc', (t) => {
let PLATFORM = ''

const _processPlatform = Object.getOwnPropertyDescriptor(process, 'platform')
Object.defineProperty(process, 'platform', {
enumerable: true,
configurable: true,
get: () => PLATFORM,
})

let REPORT = {}
const _processReport = process.report.getReport
process.report.getReport = () => REPORT

t.teardown(() => {
Object.defineProperty(process, 'platform', _processPlatform)
process.report.getReport = _processReport
})

t.test('fails when not in linux', (t) => {
PLATFORM = 'darwin'

t.throws(() => checkPlatform({ libc: 'glibc' }), { code: 'EBADPLATFORM' },
'fails for glibc when not in linux')
t.throws(() => checkPlatform({ libc: 'musl' }), { code: 'EBADPLATFORM' },
'fails for musl when not in linux')
t.end()
})

t.test('glibc', (t) => {
PLATFORM = 'linux'

REPORT = {}
t.throws(() => checkPlatform({ libc: 'glibc' }), { code: 'EBADPLATFORM' },
'fails when report is missing header property')

REPORT = { header: {} }
t.throws(() => checkPlatform({ libc: 'glibc' }), { code: 'EBADPLATFORM' },
'fails when header is missing glibcRuntimeVersion property')

REPORT = { header: { glibcRuntimeVersion: '1' } }
t.doesNotThrow(() => checkPlatform({ libc: 'glibc' }), 'allows glibc on glibc')
t.throws(() => checkPlatform({ libc: 'musl' }), { code: 'EBADPLATFORM' },
'does not allow musl on glibc')

t.end()
})

t.test('musl', (t) => {
PLATFORM = 'linux'

REPORT = {}
t.throws(() => checkPlatform({ libc: 'musl' }), { code: 'EBADPLATFORM' },
'fails when report is missing sharedObjects property')

REPORT = { sharedObjects: {} }
t.throws(() => checkPlatform({ libc: 'musl' }), { code: 'EBADPLATFORM' },
'fails when sharedObjects property is not an array')

REPORT = { sharedObjects: [] }
t.throws(() => checkPlatform({ libc: 'musl' }), { code: 'EBADPLATFORM' },
'fails when sharedObjects does not contain musl')

REPORT = { sharedObjects: ['ld-musl-foo'] }
t.doesNotThrow(() => checkPlatform({ libc: 'musl' }), 'allows musl on musl as ld-musl-')

REPORT = { sharedObjects: ['libc.musl-'] }
t.doesNotThrow(() => checkPlatform({ libc: 'musl' }), 'allows musl on musl as libc.musl-')

t.throws(() => checkPlatform({ libc: 'glibc' }), { code: 'EBADPLATFORM' },
'does not allow glibc on musl')

t.end()
})

t.end()
})

0 comments on commit 1b6f3e4

Please sign in to comment.