mirror of
https://github.com/lovell/sharp.git
synced 2025-07-13 12:20:13 +02:00
Verify platform of vendor binaries at install and run time
This commit is contained in:
parent
57946ed672
commit
7b6c80327e
118
binding.js
118
binding.js
@ -10,24 +10,15 @@ const semver = require('semver');
|
|||||||
const tar = require('tar');
|
const tar = require('tar');
|
||||||
const detectLibc = require('detect-libc');
|
const detectLibc = require('detect-libc');
|
||||||
|
|
||||||
|
const platform = require('./lib/platform');
|
||||||
|
|
||||||
// Use NPM-provided environment variable where available, falling back to require-based method for Electron
|
// Use NPM-provided environment variable where available, falling back to require-based method for Electron
|
||||||
const minimumLibvipsVersion = process.env.npm_package_config_libvips || require('./package.json').config.libvips;
|
const minimumLibvipsVersion = process.env.npm_package_config_libvips || require('./package.json').config.libvips;
|
||||||
|
|
||||||
const distBaseUrl = process.env.SHARP_DIST_BASE_URL || `https://github.com/lovell/sharp-libvips/releases/download/v${minimumLibvipsVersion}/`;
|
const distBaseUrl = process.env.SHARP_DIST_BASE_URL || `https://github.com/lovell/sharp-libvips/releases/download/v${minimumLibvipsVersion}/`;
|
||||||
|
|
||||||
const platform = process.env.npm_config_platform || process.platform;
|
|
||||||
|
|
||||||
const arch = process.env.npm_config_arch || process.arch;
|
|
||||||
|
|
||||||
// -- Helpers
|
// -- Helpers
|
||||||
|
|
||||||
// Does this file exist?
|
|
||||||
const isFile = function (file) {
|
|
||||||
try {
|
|
||||||
return fs.statSync(file).isFile();
|
|
||||||
} catch (err) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
const unpack = function (tarPath, done) {
|
const unpack = function (tarPath, done) {
|
||||||
const vendorPath = path.join(__dirname, 'vendor');
|
const vendorPath = path.join(__dirname, 'vendor');
|
||||||
fs.mkdirSync(vendorPath);
|
fs.mkdirSync(vendorPath);
|
||||||
@ -41,73 +32,68 @@ const unpack = function (tarPath, done) {
|
|||||||
.catch(error);
|
.catch(error);
|
||||||
};
|
};
|
||||||
|
|
||||||
const platformId = function () {
|
|
||||||
const platformId = [platform];
|
|
||||||
if (arch === 'arm' || arch === 'armhf' || arch === 'arm64') {
|
|
||||||
const armVersion = (arch === 'arm64') ? '8' : process.env.npm_config_armv || process.config.variables.arm_version || '6';
|
|
||||||
platformId.push('armv' + armVersion);
|
|
||||||
} else {
|
|
||||||
platformId.push(arch);
|
|
||||||
}
|
|
||||||
return platformId.join('-');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Error
|
|
||||||
const error = function (msg) {
|
const error = function (msg) {
|
||||||
if (msg instanceof Error) {
|
if (msg instanceof Error) {
|
||||||
msg = msg.message;
|
msg = msg.message;
|
||||||
}
|
}
|
||||||
process.stderr.write('ERROR: ' + msg + '\n');
|
process.stderr.write(`sharp: ${msg}\n`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// -- Binary downloaders
|
// -- Binary downloaders
|
||||||
|
|
||||||
module.exports.download_vips = function () {
|
module.exports.download_vips = function () {
|
||||||
// Has vips been installed locally?
|
// Check for existing vendored binaries and verify platform matches
|
||||||
const vipsHeaderPath = path.join(__dirname, 'vendor', 'include', 'vips', 'vips.h');
|
const currentPlatformId = platform();
|
||||||
if (!isFile(vipsHeaderPath)) {
|
try {
|
||||||
// Ensure Intel 64-bit or ARM
|
const vendorPlatformId = require(path.join(__dirname, 'vendor', 'platform.json'));
|
||||||
if (arch === 'ia32') {
|
if (currentPlatformId === vendorPlatformId) {
|
||||||
error('Intel Architecture 32-bit systems require manual installation of libvips - please see http://sharp.dimens.io/page/install');
|
return;
|
||||||
|
} else {
|
||||||
|
error(`'${vendorPlatformId}' binaries cannot be used on the '${currentPlatformId}' platform. Please remove the 'node_modules/sharp/vendor' directory and run 'npm install'.`);
|
||||||
}
|
}
|
||||||
// Ensure glibc Linux
|
} catch (err) {}
|
||||||
if (detectLibc.isNonGlibcLinux) {
|
// Ensure Intel 64-bit or ARM
|
||||||
error(`Use with ${detectLibc.family} libc requires manual installation of libvips - please see http://sharp.dimens.io/page/install`);
|
const arch = process.env.npm_config_arch || process.arch;
|
||||||
}
|
if (arch === 'ia32') {
|
||||||
// Ensure glibc >= 2.13
|
error('Intel Architecture 32-bit systems require manual installation of libvips - please see http://sharp.dimens.io/page/install');
|
||||||
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version && semver.lt(`${detectLibc.version}.0`, '2.13.0')) {
|
|
||||||
error(`Use with glibc version ${detectLibc.version} requires manual installation of libvips - please see http://sharp.dimens.io/page/install`);
|
|
||||||
}
|
|
||||||
// Arch/platform-specific .tar.gz
|
|
||||||
const tarFilename = ['libvips', minimumLibvipsVersion, platformId()].join('-') + '.tar.gz';
|
|
||||||
// Download to per-process temporary file
|
|
||||||
const tarPathTemp = path.join(os.tmpdir(), process.pid + '-' + tarFilename);
|
|
||||||
const tmpFile = fs.createWriteStream(tarPathTemp).on('finish', function () {
|
|
||||||
unpack(tarPathTemp, function () {
|
|
||||||
// Attempt to remove temporary file
|
|
||||||
try {
|
|
||||||
fs.unlinkSync(tarPathTemp);
|
|
||||||
} catch (err) {}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const url = distBaseUrl + tarFilename;
|
|
||||||
const simpleGetOpt = {
|
|
||||||
url: url,
|
|
||||||
agent: caw(null, {
|
|
||||||
protocol: 'https'
|
|
||||||
})
|
|
||||||
};
|
|
||||||
simpleGet(simpleGetOpt, function (err, response) {
|
|
||||||
if (err) {
|
|
||||||
error('Download of ' + url + ' failed: ' + err.message);
|
|
||||||
}
|
|
||||||
if (response.statusCode !== 200) {
|
|
||||||
error(url + ' status code ' + response.statusCode);
|
|
||||||
}
|
|
||||||
response.pipe(tmpFile);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
// Ensure glibc Linux
|
||||||
|
if (detectLibc.isNonGlibcLinux) {
|
||||||
|
error(`Use with ${detectLibc.family} libc requires manual installation of libvips - please see http://sharp.dimens.io/page/install`);
|
||||||
|
}
|
||||||
|
// Ensure glibc >= 2.13
|
||||||
|
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version && semver.lt(`${detectLibc.version}.0`, '2.13.0')) {
|
||||||
|
error(`Use with glibc version ${detectLibc.version} requires manual installation of libvips - please see http://sharp.dimens.io/page/install`);
|
||||||
|
}
|
||||||
|
// Arch/platform-specific .tar.gz
|
||||||
|
const tarFilename = ['libvips', minimumLibvipsVersion, currentPlatformId].join('-') + '.tar.gz';
|
||||||
|
// Download to per-process temporary file
|
||||||
|
const tarPathTemp = path.join(os.tmpdir(), `${process.pid}-${tarFilename}`);
|
||||||
|
const tmpFile = fs.createWriteStream(tarPathTemp).on('finish', function () {
|
||||||
|
unpack(tarPathTemp, function () {
|
||||||
|
// Attempt to remove temporary file
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(tarPathTemp);
|
||||||
|
} catch (err) {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const url = distBaseUrl + tarFilename;
|
||||||
|
const simpleGetOpt = {
|
||||||
|
url: url,
|
||||||
|
agent: caw(null, {
|
||||||
|
protocol: 'https'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
simpleGet(simpleGetOpt, function (err, response) {
|
||||||
|
if (err) {
|
||||||
|
error(`${url} download failed: ${err.message}`);
|
||||||
|
}
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
error(`${url} download failed: status ${response.statusCode}`);
|
||||||
|
}
|
||||||
|
response.pipe(tmpFile);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.use_global_vips = function () {
|
module.exports.use_global_vips = function () {
|
||||||
|
@ -6,8 +6,24 @@ const stream = require('stream');
|
|||||||
const events = require('events');
|
const events = require('events');
|
||||||
const semver = require('semver');
|
const semver = require('semver');
|
||||||
const is = require('./is');
|
const is = require('./is');
|
||||||
|
const platform = require('./platform');
|
||||||
const sharp = require('../build/Release/sharp.node');
|
const sharp = require('../build/Release/sharp.node');
|
||||||
|
|
||||||
|
// Vendor platform
|
||||||
|
(function () {
|
||||||
|
let vendorPlatformId;
|
||||||
|
try {
|
||||||
|
vendorPlatformId = require('../vendor/platform.json');
|
||||||
|
} catch (err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentPlatformId = platform();
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (currentPlatformId !== vendorPlatformId) {
|
||||||
|
throw new Error(`'${vendorPlatformId}' binaries cannot be used on the '${currentPlatformId}' platform. Please remove the 'node_modules/sharp/vendor' directory and run 'npm rebuild'.`);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
// Versioning
|
// Versioning
|
||||||
let versions = {
|
let versions = {
|
||||||
vips: sharp.libvipsVersion()
|
vips: sharp.libvipsVersion()
|
||||||
@ -21,7 +37,7 @@ let versions = {
|
|||||||
}
|
}
|
||||||
// Include versions of dependencies, if present
|
// Include versions of dependencies, if present
|
||||||
try {
|
try {
|
||||||
versions = require('../vendor/lib/versions.json');
|
versions = require('../vendor/versions.json');
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
15
lib/platform.js
Normal file
15
lib/platform.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
const arch = process.env.npm_config_arch || process.arch;
|
||||||
|
const platform = process.env.npm_config_platform || process.platform;
|
||||||
|
|
||||||
|
const platformId = [platform];
|
||||||
|
if (arch === 'arm' || arch === 'armhf' || arch === 'arm64') {
|
||||||
|
const armVersion = (arch === 'arm64') ? '8' : process.env.npm_config_armv || process.config.variables.arm_version || '6';
|
||||||
|
platformId.push(`armv${armVersion}`);
|
||||||
|
} else {
|
||||||
|
platformId.push(arch);
|
||||||
|
}
|
||||||
|
return platformId.join('-');
|
||||||
|
};
|
47
test/unit/platform.js
Normal file
47
test/unit/platform.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
const platform = require('../../lib/platform');
|
||||||
|
|
||||||
|
describe('Platform-detection', function () {
|
||||||
|
it('Can override arch with npm_config_arch', function () {
|
||||||
|
process.env.npm_config_arch = 'test';
|
||||||
|
assert.strictEqual('test', platform().split('-')[1]);
|
||||||
|
delete process.env.npm_config_arch;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can override platform with npm_config_platform', function () {
|
||||||
|
process.env.npm_config_platform = 'test';
|
||||||
|
assert.strictEqual('test', platform().split('-')[0]);
|
||||||
|
delete process.env.npm_config_platform;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can override ARM version via npm_config_armv', function () {
|
||||||
|
process.env.npm_config_arch = 'arm';
|
||||||
|
process.env.npm_config_armv = 'test';
|
||||||
|
assert.strictEqual('armvtest', platform().split('-')[1]);
|
||||||
|
delete process.env.npm_config_armv;
|
||||||
|
delete process.env.npm_config_arch;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can detect ARM version via process.config', function () {
|
||||||
|
process.env.npm_config_arch = 'armhf';
|
||||||
|
const armVersion = process.config.variables.arm_version;
|
||||||
|
process.config.variables.arm_version = 'test';
|
||||||
|
assert.strictEqual('armvtest', platform().split('-')[1]);
|
||||||
|
process.config.variables.arm_version = armVersion;
|
||||||
|
delete process.env.npm_config_arch;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Defaults to ARMv6 for 32-bit', function () {
|
||||||
|
process.env.npm_config_arch = 'arm';
|
||||||
|
assert.strictEqual('armv6', platform().split('-')[1]);
|
||||||
|
delete process.env.npm_config_arch;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Defaults to ARMv8 for 64-bit', function () {
|
||||||
|
process.env.npm_config_arch = 'arm64';
|
||||||
|
assert.strictEqual('armv8', platform().split('-')[1]);
|
||||||
|
delete process.env.npm_config_arch;
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user