Skip to content

Commit c0f161b

Browse files
Luca Forstneranonrig
andauthored
fix: Manually download binary if optional dependency binary can't be found after installation (#1874)
Co-authored-by: Yagiz Nizipli <[email protected]>
1 parent be17486 commit c0f161b

File tree

3 files changed

+80
-34
lines changed

3 files changed

+80
-34
lines changed

js/helper.js

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
'use strict';
22

33
const os = require('os');
4+
const path = require('path');
5+
const fs = require('fs');
46
const childProcess = require('child_process');
57

68
const BINARY_DISTRIBUTIONS = [
@@ -13,6 +15,23 @@ const BINARY_DISTRIBUTIONS = [
1315
{ packageName: '@sentry/cli-win32-i686', subpath: 'bin/sentry-cli.exe' },
1416
];
1517

18+
/**
19+
* This convoluted function resolves the path to the manually downloaded fallback
20+
* `sentry-cli` binary in a way that can't be analysed by @vercel/nft.
21+
*
22+
* Without this, the binary can be detected as an asset and included by bundlers
23+
* that use @vercel/nft.
24+
*
25+
* @returns {string} The path to the sentry-cli binary
26+
*/
27+
function getFallbackBinaryPath() {
28+
const parts = [];
29+
parts.push(__dirname);
30+
parts.push('..');
31+
parts.push(`sentry-cli${process.platform === 'win32' ? '.exe' : ''}`);
32+
return path.resolve(...parts);
33+
}
34+
1635
function getDistributionForThisPlatform() {
1736
const arch = os.arch();
1837
const platform = os.platform();
@@ -67,11 +86,25 @@ function getDistributionForThisPlatform() {
6786
}
6887

6988
/**
70-
* This convoluted function resolves the path to the `sentry-cli` binary in a
71-
* way that can't be analysed by @vercel/nft.
89+
* Throws an error with a message stating that Sentry CLI doesn't support the current platform.
90+
*
91+
* @returns {never} nothing. It throws.
92+
*/
93+
function throwUnsupportedPlatformError() {
94+
throw new Error(
95+
`Unsupported operating system or architecture! Sentry CLI does not work on this architecture.
96+
97+
Sentry CLI supports:
98+
- Darwin (macOS)
99+
- Linux and FreeBSD on x64, x86, ia32, arm64, and arm architectures
100+
- Windows x64, x86, and ia32 architectures`
101+
);
102+
}
103+
104+
/**
105+
* Tries to find the installed Sentry CLI binary - either by looking into the relevant
106+
* optional dependencies or by trying to resolve the fallback binary.
72107
*
73-
* Without this, the binary can be detected as an asset and included by bundlers
74-
* that use @vercel/nft.
75108
* @returns {string} The path to the sentry-cli binary
76109
*/
77110
function getBinaryPath() {
@@ -82,14 +115,13 @@ function getBinaryPath() {
82115
const { packageName, subpath } = getDistributionForThisPlatform();
83116

84117
if (packageName === undefined) {
85-
throw new Error(
86-
`Unsupported operating system or architecture! Sentry CLI does not work on this architecture.
118+
throwUnsupportedPlatformError();
119+
}
87120

88-
Sentry CLI supports:
89-
- Darwin (macOS)
90-
- Linux and FreeBSD on x64, x86, ia32, arm64, and arm architectures
91-
- Windows x64, x86, and ia32 architectures`
92-
);
121+
let fallbackBinaryPath = getFallbackBinaryPath();
122+
if (fs.existsSync(fallbackBinaryPath)) {
123+
// Since the fallback got installed, the optional dependencies likely didn't get installed, so we just default to the fallback.
124+
return fallbackBinaryPath;
93125
}
94126

95127
let compatibleBinaryPath;
@@ -123,10 +155,10 @@ It seems like none of the "@sentry/cli" package's optional dependencies got inst
123155
}
124156

125157
/**
126-
* Absolute path to the sentry-cli binary (platform dependent).
127-
* @type {string}
158+
* Will be used as the binary path when defined with `mockBinaryPath`.
159+
* @type {string | undefined}
128160
*/
129-
let binaryPath = getBinaryPath();
161+
let mockedBinaryPath;
130162

131163
/**
132164
* Overrides the default binary path with a mock value, useful for testing.
@@ -136,7 +168,7 @@ let binaryPath = getBinaryPath();
136168
*/
137169
// TODO(v3): Remove this function
138170
function mockBinaryPath(mockPath) {
139-
binaryPath = mockPath;
171+
mockedBinaryPath = mockPath;
140172
}
141173

142174
/**
@@ -222,7 +254,7 @@ function prepareCommand(command, schema, options) {
222254
* @returns {string}
223255
*/
224256
function getPath() {
225-
return binaryPath;
257+
return mockedBinaryPath !== undefined ? mockedBinaryPath : getBinaryPath();
226258
}
227259

228260
/**
@@ -318,4 +350,7 @@ module.exports = {
318350
mockBinaryPath,
319351
prepareCommand,
320352
serializeOptions,
353+
getDistributionForThisPlatform,
354+
throwUnsupportedPlatformError,
355+
getFallbackBinaryPath,
321356
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"@sentry/cli-win32-x64": "2.23.1"
4040
},
4141
"scripts": {
42+
"postinstall": "node ./scripts/install.js",
4243
"fix": "npm-run-all fix:eslint fix:prettier",
4344
"fix:eslint": "eslint --fix bin/* scripts/**/*.js js/**/*.js",
4445
"fix:prettier": "prettier --write bin/* scripts/**/*.js js/**/*.js",

scripts/install.js

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22

33
'use strict';
44

5-
// TODO(v3): Remove this file
6-
7-
console.log(
8-
'DEPRECATION NOTICE: The Sentry CLI install script has been deprecated. The package now uses "optionalDependencies" instead to install architecture-compatible binaries distributed over npm.'
9-
);
10-
115
const fs = require('fs');
126
const os = require('os');
137
const path = require('path');
@@ -198,7 +192,7 @@ function validateChecksum(tempPath, name) {
198192
async function downloadBinary() {
199193
const arch = os.arch();
200194
const platform = os.platform();
201-
const outputPath = helper.getPath();
195+
const outputPath = helper.getFallbackBinaryPath();
202196

203197
if (process.env.SENTRYCLI_USE_LOCAL === '1') {
204198
try {
@@ -323,14 +317,30 @@ if (process.env.SENTRYCLI_SKIP_DOWNLOAD === '1') {
323317
process.exit(0);
324318
}
325319

326-
(async () => {
327-
try {
328-
await downloadBinary();
329-
await checkVersion();
330-
process.exit(0);
331-
} catch (e) {
332-
// eslint-disable-next-line no-console
333-
console.error(e.toString());
334-
process.exit(1);
335-
}
336-
})();
320+
const { packageName: distributionPackageName, subpath: distributionSubpath } =
321+
helper.getDistributionForThisPlatform();
322+
323+
if (distributionPackageName === undefined) {
324+
helper.throwUnsupportedPlatformError();
325+
}
326+
327+
try {
328+
require.resolve(`${distributionPackageName}/${distributionSubpath}`);
329+
// If the `resolve` call succeeds it means a binary was installed successfully via optional dependencies so we can skip the manual postinstall download.
330+
process.exit(0);
331+
} catch (e) {
332+
// Optional dependencies likely didn't get installed - proceed with fallback downloading manually
333+
logger.log(
334+
`Sentry CLI binary installation via optional dependencies was unsuccessful. Downloading manually instead.`
335+
);
336+
337+
downloadBinary()
338+
.then(() => checkVersion())
339+
.then(() => {
340+
process.exit(0);
341+
})
342+
.catch((e) => {
343+
console.error(e);
344+
process.exit(1);
345+
});
346+
}

0 commit comments

Comments
 (0)