UNPKG

5.91 kBJavaScriptView Raw
1// Copyright 2013 Lovell Fuller and others.
2// SPDX-License-Identifier: Apache-2.0
3
4'use strict';
5
6const { spawnSync } = require('node:child_process');
7const { createHash } = require('node:crypto');
8const semverCoerce = require('semver/functions/coerce');
9const semverGreaterThanOrEqualTo = require('semver/functions/gte');
10const semverSatisfies = require('semver/functions/satisfies');
11const detectLibc = require('detect-libc');
12
13const { config, engines, optionalDependencies } = require('../package.json');
14
15const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips || /* istanbul ignore next */
16 config.libvips;
17const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
18
19const prebuiltPlatforms = [
20 'darwin-arm64', 'darwin-x64',
21 'linux-arm', 'linux-arm64', 'linux-s390x', 'linux-x64',
22 'linuxmusl-arm64', 'linuxmusl-x64',
23 'win32-ia32', 'win32-x64'
24];
25
26const spawnSyncOptions = {
27 encoding: 'utf8',
28 shell: true
29};
30
31const log = (item) => {
32 if (item instanceof Error) {
33 console.error(`sharp: Installation error: ${item.message}`);
34 } else {
35 console.log(`sharp: ${item}`);
36 }
37};
38
39/* istanbul ignore next */
40const runtimeLibc = () => detectLibc.isNonGlibcLinuxSync() ? detectLibc.familySync() : '';
41
42const runtimePlatformArch = () => `${process.platform}${runtimeLibc()}-${process.arch}`;
43
44/* istanbul ignore next */
45const buildPlatformArch = () => {
46 if (isEmscripten()) {
47 return 'wasm32';
48 }
49 /* eslint camelcase: ["error", { allow: ["^npm_config_"] }] */
50 const { npm_config_arch, npm_config_platform, npm_config_libc } = process.env;
51 const libc = typeof npm_config_libc === 'string' ? npm_config_libc : runtimeLibc();
52 return `${npm_config_platform || process.platform}${libc}-${npm_config_arch || process.arch}`;
53};
54
55const buildSharpLibvipsIncludeDir = () => {
56 try {
57 return require(`@img/sharp-libvips-dev-${buildPlatformArch()}/include`);
58 } catch {
59 try {
60 return require('@img/sharp-libvips-dev/include');
61 } catch {}
62 }
63 /* istanbul ignore next */
64 return '';
65};
66
67const buildSharpLibvipsCPlusPlusDir = () => {
68 try {
69 return require('@img/sharp-libvips-dev/cplusplus');
70 } catch {}
71 /* istanbul ignore next */
72 return '';
73};
74
75const buildSharpLibvipsLibDir = () => {
76 try {
77 return require(`@img/sharp-libvips-dev-${buildPlatformArch()}/lib`);
78 } catch {
79 try {
80 return require(`@img/sharp-libvips-${buildPlatformArch()}/lib`);
81 } catch {}
82 }
83 /* istanbul ignore next */
84 return '';
85};
86
87const isUnsupportedNodeRuntime = () => {
88 /* istanbul ignore next */
89 if (process.release?.name === 'node' && process.versions) {
90 if (!semverSatisfies(process.versions.node, engines.node)) {
91 return { found: process.versions.node, expected: engines.node };
92 }
93 }
94};
95
96/* istanbul ignore next */
97const isEmscripten = () => {
98 const { CC } = process.env;
99 return Boolean(CC && CC.endsWith('/emcc'));
100};
101
102const isRosetta = () => {
103 /* istanbul ignore next */
104 if (process.platform === 'darwin' && process.arch === 'x64') {
105 const translated = spawnSync('sysctl sysctl.proc_translated', spawnSyncOptions).stdout;
106 return (translated || '').trim() === 'sysctl.proc_translated: 1';
107 }
108 return false;
109};
110
111const sha512 = (s) => createHash('sha512').update(s).digest('hex');
112
113const yarnLocator = () => {
114 try {
115 const identHash = sha512(`imgsharp-libvips-${buildPlatformArch()}`);
116 const npmVersion = semverCoerce(optionalDependencies[`@img/sharp-libvips-${buildPlatformArch()}`]).version;
117 return sha512(`${identHash}npm:${npmVersion}`).slice(0, 10);
118 } catch {}
119 return '';
120};
121
122/* istanbul ignore next */
123const spawnRebuild = () =>
124 spawnSync(`node-gyp rebuild --directory=src ${isEmscripten() ? '--nodedir=emscripten' : ''}`, {
125 ...spawnSyncOptions,
126 stdio: 'inherit'
127 }).status;
128
129const globalLibvipsVersion = () => {
130 if (process.platform !== 'win32') {
131 const globalLibvipsVersion = spawnSync('pkg-config --modversion vips-cpp', {
132 ...spawnSyncOptions,
133 env: {
134 ...process.env,
135 PKG_CONFIG_PATH: pkgConfigPath()
136 }
137 }).stdout;
138 /* istanbul ignore next */
139 return (globalLibvipsVersion || '').trim();
140 } else {
141 return '';
142 }
143};
144
145/* istanbul ignore next */
146const pkgConfigPath = () => {
147 if (process.platform !== 'win32') {
148 const brewPkgConfigPath = spawnSync(
149 'which brew >/dev/null 2>&1 && brew environment --plain | grep PKG_CONFIG_LIBDIR | cut -d" " -f2',
150 spawnSyncOptions
151 ).stdout || '';
152 return [
153 brewPkgConfigPath.trim(),
154 process.env.PKG_CONFIG_PATH,
155 '/usr/local/lib/pkgconfig',
156 '/usr/lib/pkgconfig',
157 '/usr/local/libdata/pkgconfig',
158 '/usr/libdata/pkgconfig'
159 ].filter(Boolean).join(':');
160 } else {
161 return '';
162 }
163};
164
165const skipSearch = (status, reason, logger) => {
166 if (logger) {
167 logger(`Detected ${reason}, skipping search for globally-installed libvips`);
168 }
169 return status;
170};
171
172const useGlobalLibvips = (logger) => {
173 if (Boolean(process.env.SHARP_IGNORE_GLOBAL_LIBVIPS) === true) {
174 return skipSearch(false, 'SHARP_IGNORE_GLOBAL_LIBVIPS', logger);
175 }
176 if (Boolean(process.env.SHARP_FORCE_GLOBAL_LIBVIPS) === true) {
177 return skipSearch(true, 'SHARP_FORCE_GLOBAL_LIBVIPS', logger);
178 }
179 /* istanbul ignore next */
180 if (isRosetta()) {
181 return skipSearch(false, 'Rosetta', logger);
182 }
183 const globalVipsVersion = globalLibvipsVersion();
184 return !!globalVipsVersion && /* istanbul ignore next */
185 semverGreaterThanOrEqualTo(globalVipsVersion, minimumLibvipsVersion);
186};
187
188module.exports = {
189 minimumLibvipsVersion,
190 prebuiltPlatforms,
191 buildPlatformArch,
192 buildSharpLibvipsIncludeDir,
193 buildSharpLibvipsCPlusPlusDir,
194 buildSharpLibvipsLibDir,
195 isUnsupportedNodeRuntime,
196 runtimePlatformArch,
197 log,
198 yarnLocator,
199 spawnRebuild,
200 globalLibvipsVersion,
201 pkgConfigPath,
202 useGlobalLibvips
203};