agnix 0.47.0 → 0.48.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/install.js +87 -27
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const https = require('https');
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
|
-
const { execSync } = require('child_process');
|
|
6
|
+
const { execSync, spawnSync } = require('child_process');
|
|
7
7
|
const os = require('os');
|
|
8
8
|
const crypto = require('crypto');
|
|
9
9
|
|
|
@@ -35,12 +35,10 @@ function restoreWrapperBackup(wrapperPath, wrapperBackup, installCompleted) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Get platform-specific asset name and binary name.
|
|
38
|
+
* Get platform-specific asset name and binary name. Platform and arch are
|
|
39
|
+
* parameters so tests can cover mappings other than the host's.
|
|
39
40
|
*/
|
|
40
|
-
function getPlatformInfo() {
|
|
41
|
-
const platform = os.platform();
|
|
42
|
-
const arch = os.arch();
|
|
43
|
-
|
|
41
|
+
function getPlatformInfo(platform = os.platform(), arch = os.arch()) {
|
|
44
42
|
const mapping = {
|
|
45
43
|
'darwin-arm64': {
|
|
46
44
|
asset: 'agnix-aarch64-apple-darwin.tar.gz',
|
|
@@ -55,6 +53,9 @@ function getPlatformInfo() {
|
|
|
55
53
|
},
|
|
56
54
|
'linux-x64': {
|
|
57
55
|
asset: 'agnix-x86_64-unknown-linux-gnu.tar.gz',
|
|
56
|
+
// Statically linked, so it runs on hosts whose glibc is older than the
|
|
57
|
+
// one the gnu build was linked against (issue #1371).
|
|
58
|
+
fallbackAsset: 'agnix-x86_64-unknown-linux-musl.tar.gz',
|
|
58
59
|
extractedName: 'agnix',
|
|
59
60
|
binary: 'agnix-binary',
|
|
60
61
|
},
|
|
@@ -229,11 +230,58 @@ async function verifyChecksum(archivePath, checksumUrl, deps = { downloadFile })
|
|
|
229
230
|
}
|
|
230
231
|
}
|
|
231
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Whether the installed binary can actually execute on this host. A binary
|
|
235
|
+
* built against a newer glibc than the host provides fails in the dynamic
|
|
236
|
+
* loader, which npm otherwise only surfaces on the user's first real run.
|
|
237
|
+
*/
|
|
238
|
+
function binaryRuns(binaryPath, deps = { spawnSync }) {
|
|
239
|
+
try {
|
|
240
|
+
const result = deps.spawnSync(binaryPath, ['--version'], { stdio: 'ignore' });
|
|
241
|
+
return !result.error && result.status === 0;
|
|
242
|
+
} catch (_) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Download one release asset, verify it, and place the extracted binary at
|
|
249
|
+
* `binaryPath`. Removes the archive whether or not the download succeeded.
|
|
250
|
+
*/
|
|
251
|
+
async function fetchBinary({ asset, extractedName, binDir, binaryPath }) {
|
|
252
|
+
const downloadUrl = `https://github.com/${GITHUB_REPO}/releases/download/v${VERSION}/${asset}`;
|
|
253
|
+
const archivePath = path.join(binDir, asset);
|
|
254
|
+
const extractedPath = path.join(binDir, extractedName);
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
await downloadFile(downloadUrl, archivePath);
|
|
258
|
+
await verifyChecksum(archivePath, `${downloadUrl}.sha256`);
|
|
259
|
+
console.log('Extracting...');
|
|
260
|
+
extractArchive(archivePath, binDir);
|
|
261
|
+
|
|
262
|
+
// Rename extracted binary to avoid conflict with wrapper script
|
|
263
|
+
if (fs.existsSync(extractedPath) && extractedPath !== binaryPath) {
|
|
264
|
+
fs.renameSync(extractedPath, binaryPath);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Make binary executable on Unix
|
|
268
|
+
if (os.platform() !== 'win32') {
|
|
269
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (!fs.existsSync(binaryPath)) {
|
|
273
|
+
throw new Error('Binary not found after extraction');
|
|
274
|
+
}
|
|
275
|
+
} finally {
|
|
276
|
+
// Best-effort cleanup so a failed install leaves no stale archive.
|
|
277
|
+
removeIfExists(archivePath);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
232
281
|
async function main() {
|
|
233
282
|
const platformInfo = getPlatformInfo();
|
|
234
283
|
const binDir = path.join(__dirname, 'bin');
|
|
235
284
|
const binaryPath = path.join(binDir, platformInfo.binary);
|
|
236
|
-
const extractedPath = path.join(binDir, platformInfo.extractedName);
|
|
237
285
|
const wrapperPath = path.join(binDir, 'agnix');
|
|
238
286
|
const wrapperBackup = path.join(binDir, 'agnix.backup');
|
|
239
287
|
let installCompleted = false;
|
|
@@ -249,9 +297,6 @@ async function main() {
|
|
|
249
297
|
fs.mkdirSync(binDir, { recursive: true });
|
|
250
298
|
}
|
|
251
299
|
|
|
252
|
-
const downloadUrl = `https://github.com/${GITHUB_REPO}/releases/download/v${VERSION}/${platformInfo.asset}`;
|
|
253
|
-
const archivePath = path.join(binDir, platformInfo.asset);
|
|
254
|
-
|
|
255
300
|
console.log(`Downloading agnix v${VERSION} for ${os.platform()}-${os.arch()}...`);
|
|
256
301
|
|
|
257
302
|
try {
|
|
@@ -260,14 +305,30 @@ async function main() {
|
|
|
260
305
|
fs.copyFileSync(wrapperPath, wrapperBackup);
|
|
261
306
|
}
|
|
262
307
|
|
|
263
|
-
await
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
308
|
+
await fetchBinary({
|
|
309
|
+
asset: platformInfo.asset,
|
|
310
|
+
extractedName: platformInfo.extractedName,
|
|
311
|
+
binDir,
|
|
312
|
+
binaryPath,
|
|
313
|
+
});
|
|
267
314
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
315
|
+
let runs = binaryRuns(binaryPath);
|
|
316
|
+
|
|
317
|
+
// The default Linux asset is glibc-linked, so on a host older than the
|
|
318
|
+
// build's glibc floor it cannot load at all. Retry with the static build
|
|
319
|
+
// rather than leaving behind a binary that dies in the dynamic loader.
|
|
320
|
+
if (!runs && platformInfo.fallbackAsset) {
|
|
321
|
+
console.log(
|
|
322
|
+
`Downloaded binary cannot run on this host, retrying with ${platformInfo.fallbackAsset}...`
|
|
323
|
+
);
|
|
324
|
+
removeIfExists(binaryPath);
|
|
325
|
+
await fetchBinary({
|
|
326
|
+
asset: platformInfo.fallbackAsset,
|
|
327
|
+
extractedName: platformInfo.extractedName,
|
|
328
|
+
binDir,
|
|
329
|
+
binaryPath,
|
|
330
|
+
});
|
|
331
|
+
runs = binaryRuns(binaryPath);
|
|
271
332
|
}
|
|
272
333
|
|
|
273
334
|
// Restore wrapper script if it was backed up
|
|
@@ -275,14 +336,11 @@ async function main() {
|
|
|
275
336
|
fs.renameSync(wrapperBackup, wrapperPath);
|
|
276
337
|
}
|
|
277
338
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
// Verify binary exists
|
|
284
|
-
if (!fs.existsSync(binaryPath)) {
|
|
285
|
-
throw new Error('Binary not found after extraction');
|
|
339
|
+
if (!runs) {
|
|
340
|
+
// Keep the install itself successful: some sandboxes forbid spawning
|
|
341
|
+
// during postinstall, and the binary is on disk either way.
|
|
342
|
+
console.warn('Warning: the installed agnix binary did not run on this host.');
|
|
343
|
+
console.warn('If `agnix --version` fails, build from source with: cargo install agnix-cli');
|
|
286
344
|
}
|
|
287
345
|
|
|
288
346
|
installCompleted = true;
|
|
@@ -294,8 +352,8 @@ async function main() {
|
|
|
294
352
|
console.error(' cargo install agnix-cli');
|
|
295
353
|
process.exitCode = 1;
|
|
296
354
|
} finally {
|
|
297
|
-
// Best-effort cleanup so a failed install leaves no stale
|
|
298
|
-
|
|
355
|
+
// Best-effort cleanup so a failed install leaves no stale backup. Archives
|
|
356
|
+
// are removed by fetchBinary itself.
|
|
299
357
|
try {
|
|
300
358
|
restoreWrapperBackup(wrapperPath, wrapperBackup, installCompleted);
|
|
301
359
|
} catch (_) {
|
|
@@ -309,8 +367,10 @@ if (require.main === module) {
|
|
|
309
367
|
}
|
|
310
368
|
|
|
311
369
|
module.exports = {
|
|
370
|
+
binaryRuns,
|
|
312
371
|
downloadFile,
|
|
313
372
|
extractArchive,
|
|
373
|
+
fetchBinary,
|
|
314
374
|
getPlatformInfo,
|
|
315
375
|
main,
|
|
316
376
|
parseSha256Sidecar,
|