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