libvips.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // Copyright 2013 Lovell Fuller and others.
  2. // SPDX-License-Identifier: Apache-2.0
  3. 'use strict';
  4. const fs = require('fs');
  5. const os = require('os');
  6. const path = require('path');
  7. const spawnSync = require('child_process').spawnSync;
  8. const semverCoerce = require('semver/functions/coerce');
  9. const semverGreaterThanOrEqualTo = require('semver/functions/gte');
  10. const platform = require('./platform');
  11. const { config } = require('../package.json');
  12. const env = process.env;
  13. const minimumLibvipsVersionLabelled = env.npm_package_config_libvips || /* istanbul ignore next */
  14. config.libvips;
  15. const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
  16. const spawnSyncOptions = {
  17. encoding: 'utf8',
  18. shell: true
  19. };
  20. const vendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platform());
  21. const mkdirSync = function (dirPath) {
  22. try {
  23. fs.mkdirSync(dirPath, { recursive: true });
  24. } catch (err) {
  25. /* istanbul ignore next */
  26. if (err.code !== 'EEXIST') {
  27. throw err;
  28. }
  29. }
  30. };
  31. const cachePath = function () {
  32. const npmCachePath = env.npm_config_cache || /* istanbul ignore next */
  33. (env.APPDATA ? path.join(env.APPDATA, 'npm-cache') : path.join(os.homedir(), '.npm'));
  34. mkdirSync(npmCachePath);
  35. const libvipsCachePath = path.join(npmCachePath, '_libvips');
  36. mkdirSync(libvipsCachePath);
  37. return libvipsCachePath;
  38. };
  39. const integrity = function (platformAndArch) {
  40. return env[`npm_package_config_integrity_${platformAndArch.replace('-', '_')}`] || config.integrity[platformAndArch];
  41. };
  42. const log = function (item) {
  43. if (item instanceof Error) {
  44. console.error(`sharp: Installation error: ${item.message}`);
  45. } else {
  46. console.log(`sharp: ${item}`);
  47. }
  48. };
  49. const isRosetta = function () {
  50. /* istanbul ignore next */
  51. if (process.platform === 'darwin' && process.arch === 'x64') {
  52. const translated = spawnSync('sysctl sysctl.proc_translated', spawnSyncOptions).stdout;
  53. return (translated || '').trim() === 'sysctl.proc_translated: 1';
  54. }
  55. return false;
  56. };
  57. const globalLibvipsVersion = function () {
  58. if (process.platform !== 'win32') {
  59. const globalLibvipsVersion = spawnSync('pkg-config --modversion vips-cpp', {
  60. ...spawnSyncOptions,
  61. env: {
  62. ...env,
  63. PKG_CONFIG_PATH: pkgConfigPath()
  64. }
  65. }).stdout;
  66. /* istanbul ignore next */
  67. return (globalLibvipsVersion || '').trim();
  68. } else {
  69. return '';
  70. }
  71. };
  72. const hasVendoredLibvips = function () {
  73. return fs.existsSync(vendorPath);
  74. };
  75. /* istanbul ignore next */
  76. const removeVendoredLibvips = function () {
  77. fs.rmSync(vendorPath, { recursive: true, maxRetries: 3, force: true });
  78. };
  79. /* istanbul ignore next */
  80. const pkgConfigPath = function () {
  81. if (process.platform !== 'win32') {
  82. const brewPkgConfigPath = spawnSync(
  83. 'which brew >/dev/null 2>&1 && brew environment --plain | grep PKG_CONFIG_LIBDIR | cut -d" " -f2',
  84. spawnSyncOptions
  85. ).stdout || '';
  86. return [
  87. brewPkgConfigPath.trim(),
  88. env.PKG_CONFIG_PATH,
  89. '/usr/local/lib/pkgconfig',
  90. '/usr/lib/pkgconfig',
  91. '/usr/local/libdata/pkgconfig',
  92. '/usr/libdata/pkgconfig'
  93. ].filter(Boolean).join(':');
  94. } else {
  95. return '';
  96. }
  97. };
  98. const useGlobalLibvips = function () {
  99. if (Boolean(env.SHARP_IGNORE_GLOBAL_LIBVIPS) === true) {
  100. return false;
  101. }
  102. /* istanbul ignore next */
  103. if (isRosetta()) {
  104. log('Detected Rosetta, skipping search for globally-installed libvips');
  105. return false;
  106. }
  107. const globalVipsVersion = globalLibvipsVersion();
  108. return !!globalVipsVersion && /* istanbul ignore next */
  109. semverGreaterThanOrEqualTo(globalVipsVersion, minimumLibvipsVersion);
  110. };
  111. module.exports = {
  112. minimumLibvipsVersion,
  113. minimumLibvipsVersionLabelled,
  114. cachePath,
  115. integrity,
  116. log,
  117. globalLibvipsVersion,
  118. hasVendoredLibvips,
  119. removeVendoredLibvips,
  120. pkgConfigPath,
  121. useGlobalLibvips,
  122. mkdirSync
  123. };