1 |
|
2 |
|
3 |
|
4 | 'use strict';
|
5 |
|
6 | const { spawnSync } = require('node:child_process');
|
7 | const { createHash } = require('node:crypto');
|
8 | const semverCoerce = require('semver/functions/coerce');
|
9 | const semverGreaterThanOrEqualTo = require('semver/functions/gte');
|
10 | const semverSatisfies = require('semver/functions/satisfies');
|
11 | const detectLibc = require('detect-libc');
|
12 |
|
13 | const { config, engines, optionalDependencies } = require('../package.json');
|
14 |
|
15 | const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips ||
|
16 | config.libvips;
|
17 | const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
|
18 |
|
19 | const 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 |
|
26 | const spawnSyncOptions = {
|
27 | encoding: 'utf8',
|
28 | shell: true
|
29 | };
|
30 |
|
31 | const 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 |
|
40 | const runtimeLibc = () => detectLibc.isNonGlibcLinuxSync() ? detectLibc.familySync() : '';
|
41 |
|
42 | const runtimePlatformArch = () => `${process.platform}${runtimeLibc()}-${process.arch}`;
|
43 |
|
44 |
|
45 | const buildPlatformArch = () => {
|
46 | if (isEmscripten()) {
|
47 | return 'wasm32';
|
48 | }
|
49 |
|
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 |
|
55 | const 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 |
|
64 | return '';
|
65 | };
|
66 |
|
67 | const buildSharpLibvipsCPlusPlusDir = () => {
|
68 | try {
|
69 | return require('@img/sharp-libvips-dev/cplusplus');
|
70 | } catch {}
|
71 |
|
72 | return '';
|
73 | };
|
74 |
|
75 | const 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 |
|
84 | return '';
|
85 | };
|
86 |
|
87 | const isUnsupportedNodeRuntime = () => {
|
88 |
|
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 |
|
97 | const isEmscripten = () => {
|
98 | const { CC } = process.env;
|
99 | return Boolean(CC && CC.endsWith('/emcc'));
|
100 | };
|
101 |
|
102 | const isRosetta = () => {
|
103 |
|
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 |
|
111 | const sha512 = (s) => createHash('sha512').update(s).digest('hex');
|
112 |
|
113 | const 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 |
|
123 | const spawnRebuild = () =>
|
124 | spawnSync(`node-gyp rebuild --directory=src ${isEmscripten() ? '--nodedir=emscripten' : ''}`, {
|
125 | ...spawnSyncOptions,
|
126 | stdio: 'inherit'
|
127 | }).status;
|
128 |
|
129 | const 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 |
|
139 | return (globalLibvipsVersion || '').trim();
|
140 | } else {
|
141 | return '';
|
142 | }
|
143 | };
|
144 |
|
145 |
|
146 | const 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 |
|
165 | const skipSearch = (status, reason, logger) => {
|
166 | if (logger) {
|
167 | logger(`Detected ${reason}, skipping search for globally-installed libvips`);
|
168 | }
|
169 | return status;
|
170 | };
|
171 |
|
172 | const 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 |
|
180 | if (isRosetta()) {
|
181 | return skipSearch(false, 'Rosetta', logger);
|
182 | }
|
183 | const globalVipsVersion = globalLibvipsVersion();
|
184 | return !!globalVipsVersion &&
|
185 | semverGreaterThanOrEqualTo(globalVipsVersion, minimumLibvipsVersion);
|
186 | };
|
187 |
|
188 | module.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 | };
|