libvips.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. 'use strict';
  2. const fs = require('fs');
  3. const os = require('os');
  4. const path = require('path');
  5. const detectLibc = require('detect-libc');
  6. const npmLog = require('npmlog');
  7. const semver = require('semver');
  8. const simpleGet = require('simple-get');
  9. const tar = require('tar');
  10. const agent = require('../lib/agent');
  11. const libvips = require('../lib/libvips');
  12. const platform = require('../lib/platform');
  13. const minimumGlibcVersionByArch = {
  14. arm: '2.28',
  15. arm64: '2.29',
  16. x64: '2.17'
  17. };
  18. const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
  19. const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `https://github.com/lovell/sharp-libvips/releases/download/v${minimumLibvipsVersionLabelled}/`;
  20. const fail = function (err) {
  21. npmLog.error('sharp', err.message);
  22. if (err.code === 'EACCES') {
  23. npmLog.info('sharp', 'Are you trying to install as a root or sudo user? Try again with the --unsafe-perm flag');
  24. }
  25. npmLog.info('sharp', 'Attempting to build from source via node-gyp but this may fail due to the above error');
  26. npmLog.info('sharp', 'Please see https://sharp.pixelplumbing.com/install for required dependencies');
  27. process.exit(1);
  28. };
  29. const extractTarball = function (tarPath) {
  30. const vendorPath = path.join(__dirname, '..', 'vendor');
  31. libvips.mkdirSync(vendorPath);
  32. tar
  33. .extract({
  34. file: tarPath,
  35. cwd: vendorPath,
  36. strict: true
  37. })
  38. .catch(function (err) {
  39. if (/unexpected end of file/.test(err.message)) {
  40. npmLog.error('sharp', `Please delete ${tarPath} as it is not a valid tarball`);
  41. }
  42. fail(err);
  43. });
  44. };
  45. try {
  46. const useGlobalLibvips = libvips.useGlobalLibvips();
  47. if (useGlobalLibvips) {
  48. const globalLibvipsVersion = libvips.globalLibvipsVersion();
  49. npmLog.info('sharp', `Detected globally-installed libvips v${globalLibvipsVersion}`);
  50. npmLog.info('sharp', 'Building from source via node-gyp');
  51. process.exit(1);
  52. } else if (libvips.hasVendoredLibvips()) {
  53. npmLog.info('sharp', `Using existing vendored libvips v${minimumLibvipsVersion}`);
  54. } else {
  55. // Is this arch/platform supported?
  56. const arch = process.env.npm_config_arch || process.arch;
  57. const platformAndArch = platform();
  58. if (arch === 'ia32' && !platformAndArch.startsWith('win32')) {
  59. throw new Error(`Intel Architecture 32-bit systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
  60. }
  61. if (platformAndArch === 'freebsd-x64' || platformAndArch === 'openbsd-x64' || platformAndArch === 'sunos-x64') {
  62. throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
  63. }
  64. if (detectLibc.family === detectLibc.GLIBC && detectLibc.version) {
  65. if (semver.lt(`${detectLibc.version}.0`, `${minimumGlibcVersionByArch[arch]}.0`)) {
  66. throw new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
  67. }
  68. }
  69. // Download to per-process temporary file
  70. const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.gz';
  71. const tarPathCache = path.join(libvips.cachePath(), tarFilename);
  72. if (fs.existsSync(tarPathCache)) {
  73. npmLog.info('sharp', `Using cached ${tarPathCache}`);
  74. extractTarball(tarPathCache);
  75. } else {
  76. const tarPathTemp = path.join(os.tmpdir(), `${process.pid}-${tarFilename}`);
  77. const tmpFile = fs.createWriteStream(tarPathTemp);
  78. const url = distBaseUrl + tarFilename;
  79. npmLog.info('sharp', `Downloading ${url}`);
  80. simpleGet({ url: url, agent: agent() }, function (err, response) {
  81. if (err) {
  82. fail(err);
  83. } else if (response.statusCode === 404) {
  84. fail(new Error(`Prebuilt libvips ${minimumLibvipsVersion} binaries are not yet available for ${platformAndArch}`));
  85. } else if (response.statusCode !== 200) {
  86. fail(new Error(`Status ${response.statusCode} ${response.statusMessage}`));
  87. } else {
  88. response
  89. .on('error', fail)
  90. .pipe(tmpFile);
  91. }
  92. });
  93. tmpFile
  94. .on('error', fail)
  95. .on('close', function () {
  96. try {
  97. // Attempt to rename
  98. fs.renameSync(tarPathTemp, tarPathCache);
  99. } catch (err) {
  100. // Fall back to copy and unlink
  101. fs.copyFileSync(tarPathTemp, tarPathCache);
  102. fs.unlinkSync(tarPathTemp);
  103. }
  104. extractTarball(tarPathCache);
  105. });
  106. }
  107. }
  108. } catch (err) {
  109. fail(err);
  110. }