diff --git a/lib/download/npm.js b/lib/download/npm.js index f86dbc7a..03b8f64d 100644 --- a/lib/download/npm.js +++ b/lib/download/npm.js @@ -246,6 +246,17 @@ async function download(pkg, options) { err.name = 'UnSupportedPlatformError'; throw err; } + // dont download pkg in not matched libc + if (Array.isArray(pkg.libc)) { + const currentLibc = utils.getLibc(); + debug('currentLibc', currentLibc, pkg.libc); + if (!utils.matchPlatform(currentLibc, pkg.libc)) { + const errMsg = `[${pkg.name}@${pkg.version}] skip download for reason ${pkg.libc.join(', ')} dont includes your libc ${currentLibc}`; + const err = new Error(errMsg); + err.name = 'UnSupportedPlatformError'; + throw err; + } + } const ungzipDir = options.ungzipDir || utils.getPackageStorePath(options.storeDir, pkg); diff --git a/lib/utils.js b/lib/utils.js index 9c1f4789..7033d6df 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -463,7 +463,26 @@ exports.getBugVersions = async (registry, globalOptions) => { return pkg.config['bug-versions']; }; -// match platform or arch +// detect libc +// follow yarn impl: https://github.com/yarnpkg/berry/pull/3981/files#diff-f9ba955128e960171ac97ce06b0b0a940bb074af2794429a9f03c75f2a3bd459R10 +exports.getLibc = () => { + if (process.platform === 'win32') return null; + const report = process.report && process.report.getReport() || {}; + const sharedObjects = report.sharedObjects || []; + + // Matches the first group if libc, second group if musl + const libcRE = /\/(?:(ld-linux-|[^/]+-linux-gnu\/)|(libc.musl-|ld-musl-))/i; + for (const sharedObject of sharedObjects) { + const m = sharedObject.match(libcRE); + if (m) { + if (m[1]) return 'libc'; + if (m[2]) return 'musl'; + } + } + return null; +}; + +// match platform, arch or libc // see https://docs.npmjs.com/cli/v7/configuring-npm/package-json#os exports.matchPlatform = (current, osNames) => { if (!Array.isArray(osNames) || osNames.length === 0) { diff --git a/test/utils.test.js b/test/utils.test.js index a90dc519..fcd35bd9 100644 --- a/test/utils.test.js +++ b/test/utils.test.js @@ -31,6 +31,20 @@ describe('test/utils.test.js', () => { assert(utils.matchPlatform('x64', [ 'x64', '!x64' ])); }); + it('should match libc names', () => { + assert(utils.matchPlatform('glibc', [])); + assert(utils.matchPlatform('musl', [])); + assert(utils.matchPlatform(null, [])); + assert(utils.matchPlatform('glibc', [ 'glibc' ])); + assert(utils.matchPlatform('glibc', [ 'glibc', 'musl' ])); + assert(utils.matchPlatform('musl', [ 'glibc', 'musl' ])); + assert(utils.matchPlatform('musl', [ 'musl' ])); + assert(utils.matchPlatform('glibc', [ '!musl' ])); + assert(utils.matchPlatform('musl', [ '!glibc' ])); + assert(utils.matchPlatform('glibc', [ '!musl', 'glibc' ])); + assert(utils.matchPlatform('glibc', [ 'glibc', '!glibc' ])); + }); + it('should not match os names', () => { assert(!utils.matchPlatform('darwin', [ 'linux' ])); assert(!utils.matchPlatform('darwin', [ 'win32' ])); @@ -53,6 +67,15 @@ describe('test/utils.test.js', () => { assert(!utils.matchPlatform('mips', [ '!x64', '!mips' ])); assert(!utils.matchPlatform('x64', [ '!x64' ])); }); + + it('should not match libc names', () => { + assert(!utils.matchPlatform(null, [ 'musl' ])); + assert(!utils.matchPlatform(null, [ 'glibc' ])); + assert(!utils.matchPlatform('glibc', [ 'musl' ])); + assert(!utils.matchPlatform('musl', [ 'glibc' ])); + assert(!utils.matchPlatform('glibc', [ '!glibc' ])); + assert(!utils.matchPlatform('musl', [ '!musl' ])); + }); }); describe('findMaxSatisfyingVersion()', () => {