redblue-cli 0.1.0-next.50 → 0.1.0-next.52
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/README.md +7 -2
- package/package.json +1 -1
- package/sdk/redblue-sdk.js +374 -26
package/README.md
CHANGED
|
@@ -156,6 +156,11 @@ npm exec --package redblue-cli rb -- tls security audit github.com
|
|
|
156
156
|
# Install the wrapper in a project
|
|
157
157
|
npm install redblue-cli
|
|
158
158
|
npx rb network ports scan 192.168.1.1 --preset common
|
|
159
|
+
|
|
160
|
+
# Let the wrapper manage the release binary
|
|
161
|
+
npx redblue-cli --install --print-binary-path
|
|
162
|
+
npx redblue-cli --check-update
|
|
163
|
+
npx redblue-cli --upgrade --channel next
|
|
159
164
|
```
|
|
160
165
|
|
|
161
166
|
```js
|
|
@@ -633,9 +638,9 @@ const { createClient } = require('redblue-cli');
|
|
|
633
638
|
})();
|
|
634
639
|
```
|
|
635
640
|
|
|
636
|
-
If you want the wrapper to manage the binary for you, use `autoDownload: true` with a `targetDir`.
|
|
641
|
+
If you want the wrapper to manage the binary for you, use `--install`, `--check-update`, or `--upgrade`. Managed installs default to `~/.local/bin`, and the wrapper still detects legacy installs in `~/.redblue/bin`. For SDK consumers, `autoDownload: true` still works and can be combined with a custom `targetDir`.
|
|
637
642
|
|
|
638
|
-
> **Note:** the exact command `npx rb` works after `redblue-cli` is installed in the project or globally. For zero-install usage, prefer `npx redblue-cli ...` or `npm exec --package redblue-cli rb -- ...`.
|
|
643
|
+
> **Note:** the exact command `npx rb` works after `redblue-cli` is installed in the project or globally. For zero-install usage, prefer `npx redblue-cli ...` or `npm exec --package redblue-cli rb -- ...`. Use bare `rb --version` to query the real binary version; use wrapper `--version <tag>` or `--release-version <tag>` before the command when you want to pin a release download.
|
|
639
644
|
|
|
640
645
|
### Build from Source
|
|
641
646
|
|
package/package.json
CHANGED
package/sdk/redblue-sdk.js
CHANGED
|
@@ -20,13 +20,19 @@ const WRAPPER_OPTION_TYPES = Object.freeze({
|
|
|
20
20
|
'auto-download': 'boolean',
|
|
21
21
|
'binary-path': 'string',
|
|
22
22
|
channel: 'string',
|
|
23
|
+
'check-update': 'boolean',
|
|
23
24
|
download: 'boolean',
|
|
25
|
+
force: 'boolean',
|
|
24
26
|
'github-token': 'string',
|
|
27
|
+
install: 'boolean',
|
|
25
28
|
'no-verify': 'boolean',
|
|
29
|
+
'print-binary-path': 'boolean',
|
|
30
|
+
'release-version': 'string',
|
|
26
31
|
repo: 'string',
|
|
27
32
|
'sdk-help': 'boolean',
|
|
28
33
|
'static-build': 'boolean',
|
|
29
34
|
'target-dir': 'string',
|
|
35
|
+
upgrade: 'boolean',
|
|
30
36
|
version: 'string',
|
|
31
37
|
verify: 'boolean'
|
|
32
38
|
});
|
|
@@ -45,12 +51,28 @@ const WRAPPER_OPTION_SCHEMA = Object.freeze({
|
|
|
45
51
|
channel: {
|
|
46
52
|
type: 'string'
|
|
47
53
|
},
|
|
54
|
+
'check-update': {
|
|
55
|
+
type: 'boolean'
|
|
56
|
+
},
|
|
48
57
|
'github-token': {
|
|
49
58
|
type: 'string'
|
|
50
59
|
},
|
|
60
|
+
force: {
|
|
61
|
+
type: 'boolean'
|
|
62
|
+
},
|
|
63
|
+
install: {
|
|
64
|
+
type: 'boolean'
|
|
65
|
+
},
|
|
51
66
|
repo: {
|
|
52
67
|
type: 'string'
|
|
53
68
|
},
|
|
69
|
+
'print-binary-path': {
|
|
70
|
+
type: 'boolean'
|
|
71
|
+
},
|
|
72
|
+
'release-version': {
|
|
73
|
+
type: 'string',
|
|
74
|
+
aliases: ['version']
|
|
75
|
+
},
|
|
54
76
|
'sdk-help': {
|
|
55
77
|
type: 'boolean'
|
|
56
78
|
},
|
|
@@ -60,8 +82,8 @@ const WRAPPER_OPTION_SCHEMA = Object.freeze({
|
|
|
60
82
|
'target-dir': {
|
|
61
83
|
type: 'string'
|
|
62
84
|
},
|
|
63
|
-
|
|
64
|
-
type: '
|
|
85
|
+
upgrade: {
|
|
86
|
+
type: 'boolean'
|
|
65
87
|
},
|
|
66
88
|
verify: {
|
|
67
89
|
type: 'boolean'
|
|
@@ -122,9 +144,31 @@ function resolveFromPath(binaryName) {
|
|
|
122
144
|
}
|
|
123
145
|
|
|
124
146
|
function defaultInstallDir() {
|
|
147
|
+
return process.env.REDBLUE_INSTALL_DIR || process.env.INSTALL_DIR || path.join(os.homedir(), '.local', 'bin');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function legacyInstallDir() {
|
|
125
151
|
return path.join(os.homedir(), '.redblue', 'bin');
|
|
126
152
|
}
|
|
127
153
|
|
|
154
|
+
function resolveManagedBinaryPath(options = {}) {
|
|
155
|
+
if (options.binaryPath) {
|
|
156
|
+
return path.resolve(options.binaryPath);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const installDir = options.targetDir || defaultInstallDir();
|
|
160
|
+
const binaryName = options.binaryName || DEFAULT_BINARY_NAME;
|
|
161
|
+
return path.resolve(installDir, binaryName);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function resolveLegacyBinaryPath(options = {}) {
|
|
165
|
+
if (options.binaryPath || options.targetDir) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return path.resolve(legacyInstallDir(), options.binaryName || DEFAULT_BINARY_NAME);
|
|
170
|
+
}
|
|
171
|
+
|
|
128
172
|
function resolveAssetName(options = {}) {
|
|
129
173
|
const platform = options.platform || process.platform;
|
|
130
174
|
const arch = options.arch || process.arch;
|
|
@@ -203,13 +247,15 @@ async function requestText(url, options = {}) {
|
|
|
203
247
|
|
|
204
248
|
async function getReleaseTag(options = {}) {
|
|
205
249
|
const repo = options.repo || DEFAULT_REPO;
|
|
206
|
-
const githubToken =
|
|
250
|
+
const githubToken =
|
|
251
|
+
options.githubToken || (options.env && options.env.GITHUB_TOKEN) || process.env.GITHUB_TOKEN;
|
|
207
252
|
const headers = githubToken ? { Authorization: `Bearer ${githubToken}` } : {};
|
|
253
|
+
const requestedVersion = options.releaseVersion || options.version;
|
|
208
254
|
|
|
209
|
-
if (
|
|
210
|
-
return String(
|
|
211
|
-
? String(
|
|
212
|
-
: `v${
|
|
255
|
+
if (requestedVersion) {
|
|
256
|
+
return String(requestedVersion).startsWith('v')
|
|
257
|
+
? String(requestedVersion)
|
|
258
|
+
: `v${requestedVersion}`;
|
|
213
259
|
}
|
|
214
260
|
|
|
215
261
|
const channel = options.channel || 'stable';
|
|
@@ -281,9 +327,7 @@ async function verifyChecksum(filePath, checksumUrl, options = {}) {
|
|
|
281
327
|
async function downloadBinary(options = {}) {
|
|
282
328
|
const repo = options.repo || DEFAULT_REPO;
|
|
283
329
|
const assetName = options.assetName || resolveAssetName(options);
|
|
284
|
-
const
|
|
285
|
-
const binaryName = options.binaryName || DEFAULT_BINARY_NAME;
|
|
286
|
-
const destination = path.resolve(installDir, binaryName);
|
|
330
|
+
const destination = resolveManagedBinaryPath(options);
|
|
287
331
|
const releaseTag = await getReleaseTag(options);
|
|
288
332
|
const githubToken = options.githubToken || process.env.GITHUB_TOKEN;
|
|
289
333
|
const headers = githubToken ? { Authorization: `Bearer ${githubToken}` } : {};
|
|
@@ -303,29 +347,48 @@ async function downloadBinary(options = {}) {
|
|
|
303
347
|
return destination;
|
|
304
348
|
}
|
|
305
349
|
|
|
306
|
-
async function
|
|
350
|
+
async function resolveBinaryWithInfo(options = {}) {
|
|
307
351
|
if (options.binaryPath) {
|
|
308
352
|
const binaryPath = path.resolve(options.binaryPath);
|
|
309
353
|
if (!exists(binaryPath)) {
|
|
310
354
|
throw new Error(`redblue binary not found at ${binaryPath}`);
|
|
311
355
|
}
|
|
312
|
-
return
|
|
356
|
+
return {
|
|
357
|
+
binaryPath,
|
|
358
|
+
source: 'explicit'
|
|
359
|
+
};
|
|
313
360
|
}
|
|
314
361
|
|
|
315
|
-
const installDir = options.targetDir || defaultInstallDir();
|
|
316
362
|
const binaryName = options.binaryName || DEFAULT_BINARY_NAME;
|
|
317
|
-
const installedCandidate =
|
|
363
|
+
const installedCandidate = resolveManagedBinaryPath(options);
|
|
318
364
|
if (exists(installedCandidate)) {
|
|
319
|
-
return
|
|
365
|
+
return {
|
|
366
|
+
binaryPath: installedCandidate,
|
|
367
|
+
source: 'managed'
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const legacyCandidate = resolveLegacyBinaryPath(options);
|
|
372
|
+
if (legacyCandidate && exists(legacyCandidate)) {
|
|
373
|
+
return {
|
|
374
|
+
binaryPath: legacyCandidate,
|
|
375
|
+
source: 'legacy'
|
|
376
|
+
};
|
|
320
377
|
}
|
|
321
378
|
|
|
322
379
|
const pathCandidate = resolveFromPath(binaryName);
|
|
323
380
|
if (pathCandidate) {
|
|
324
|
-
return
|
|
381
|
+
return {
|
|
382
|
+
binaryPath: pathCandidate,
|
|
383
|
+
source: 'path'
|
|
384
|
+
};
|
|
325
385
|
}
|
|
326
386
|
|
|
327
387
|
if (options.autoDownload) {
|
|
328
|
-
return
|
|
388
|
+
return {
|
|
389
|
+
binaryPath: await downloadBinary(options),
|
|
390
|
+
source: 'downloaded'
|
|
391
|
+
};
|
|
329
392
|
}
|
|
330
393
|
|
|
331
394
|
throw new Error(
|
|
@@ -333,6 +396,152 @@ async function resolveBinary(options = {}) {
|
|
|
333
396
|
);
|
|
334
397
|
}
|
|
335
398
|
|
|
399
|
+
async function resolveBinary(options = {}) {
|
|
400
|
+
const resolved = await resolveBinaryWithInfo(options);
|
|
401
|
+
return resolved.binaryPath;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function normalizeReleaseTag(value) {
|
|
405
|
+
if (!value) {
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const stringValue = String(value).trim();
|
|
410
|
+
if (!stringValue) {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return stringValue.startsWith('v') ? stringValue : `v${stringValue}`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function parseInstalledVersion(output) {
|
|
418
|
+
const text = String(output || '').trim();
|
|
419
|
+
if (!text) {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const match = text.match(/\bv\d+\.\d+\.\d+(?:[-+][^\s]+)?\b/);
|
|
424
|
+
if (match) {
|
|
425
|
+
return match[0];
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const bare = text.match(/\b\d+\.\d+\.\d+(?:[-+][^\s]+)?\b/);
|
|
429
|
+
return bare ? `v${bare[0]}` : null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
async function getInstalledVersion(binaryPath, options = {}) {
|
|
433
|
+
try {
|
|
434
|
+
const result = await execFilePromise(binaryPath, ['--version'], options);
|
|
435
|
+
return parseInstalledVersion(result.stdout || result.stderr);
|
|
436
|
+
} catch (_) {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
async function getBinaryInfo(options = {}) {
|
|
442
|
+
const resolved = await resolveBinaryWithInfo(options);
|
|
443
|
+
const version = await getInstalledVersion(resolved.binaryPath, options);
|
|
444
|
+
return {
|
|
445
|
+
binaryPath: resolved.binaryPath,
|
|
446
|
+
source: resolved.source,
|
|
447
|
+
version
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function resolveManagedUpgradeDestination(options = {}, currentInfo = null) {
|
|
452
|
+
if (options.binaryPath) {
|
|
453
|
+
return path.resolve(options.binaryPath);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (options.targetDir) {
|
|
457
|
+
return resolveManagedBinaryPath(options);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (currentInfo && (currentInfo.source === 'managed' || currentInfo.source === 'legacy')) {
|
|
461
|
+
return currentInfo.binaryPath;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return resolveManagedBinaryPath(options);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
async function ensureInstalled(options = {}) {
|
|
468
|
+
try {
|
|
469
|
+
const info = await getBinaryInfo(Object.assign({}, options, { autoDownload: false }));
|
|
470
|
+
return Object.assign({ changed: false }, info);
|
|
471
|
+
} catch (_) {
|
|
472
|
+
const releaseTag = normalizeReleaseTag(options.releaseVersion || options.version) || (await getReleaseTag(options));
|
|
473
|
+
const binaryPath = await downloadBinary(
|
|
474
|
+
Object.assign({}, options, {
|
|
475
|
+
version: releaseTag
|
|
476
|
+
})
|
|
477
|
+
);
|
|
478
|
+
return {
|
|
479
|
+
binaryPath,
|
|
480
|
+
source: 'downloaded',
|
|
481
|
+
version: releaseTag,
|
|
482
|
+
changed: true
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
async function checkForUpdates(options = {}) {
|
|
488
|
+
const releaseTag = await getReleaseTag(options);
|
|
489
|
+
let current = null;
|
|
490
|
+
|
|
491
|
+
try {
|
|
492
|
+
current = await getBinaryInfo(Object.assign({}, options, { autoDownload: false }));
|
|
493
|
+
} catch (_) {
|
|
494
|
+
current = null;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return {
|
|
498
|
+
binaryPath: current ? current.binaryPath : resolveManagedBinaryPath(options),
|
|
499
|
+
currentVersion: current ? current.version : null,
|
|
500
|
+
latestVersion: releaseTag,
|
|
501
|
+
source: current ? current.source : null,
|
|
502
|
+
hasUpdate: !current || current.version !== releaseTag
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
async function upgradeBinary(options = {}) {
|
|
507
|
+
const releaseTag = await getReleaseTag(options);
|
|
508
|
+
let current = null;
|
|
509
|
+
|
|
510
|
+
try {
|
|
511
|
+
current = await getBinaryInfo(Object.assign({}, options, { autoDownload: false }));
|
|
512
|
+
} catch (_) {
|
|
513
|
+
current = null;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const destination = resolveManagedUpgradeDestination(options, current);
|
|
517
|
+
const currentVersion = current ? current.version : null;
|
|
518
|
+
const needsDownload = options.force === true || !exists(destination) || currentVersion !== releaseTag;
|
|
519
|
+
|
|
520
|
+
if (!needsDownload) {
|
|
521
|
+
return {
|
|
522
|
+
binaryPath: destination,
|
|
523
|
+
previousVersion: currentVersion,
|
|
524
|
+
version: releaseTag,
|
|
525
|
+
changed: false,
|
|
526
|
+
source: current.source
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const binaryPath = await downloadBinary(
|
|
531
|
+
Object.assign({}, options, {
|
|
532
|
+
binaryPath: destination
|
|
533
|
+
})
|
|
534
|
+
);
|
|
535
|
+
|
|
536
|
+
return {
|
|
537
|
+
binaryPath,
|
|
538
|
+
previousVersion: currentVersion,
|
|
539
|
+
version: releaseTag,
|
|
540
|
+
changed: true,
|
|
541
|
+
source: current ? current.source : 'managed'
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
|
|
336
545
|
function execFilePromise(binaryPath, args, options = {}) {
|
|
337
546
|
return new Promise((resolve, reject) => {
|
|
338
547
|
execFile(
|
|
@@ -461,6 +670,18 @@ function splitWrapperArgs(argv) {
|
|
|
461
670
|
break;
|
|
462
671
|
}
|
|
463
672
|
|
|
673
|
+
if (optionType === 'string' && eqIndex === -1) {
|
|
674
|
+
const nextToken = rawArgs[index + 1];
|
|
675
|
+
if (optionName === 'version' && (!nextToken || String(nextToken).startsWith('-'))) {
|
|
676
|
+
break;
|
|
677
|
+
}
|
|
678
|
+
if (nextToken === undefined) {
|
|
679
|
+
wrapperArgs.push(token);
|
|
680
|
+
index += 1;
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
464
685
|
wrapperArgs.push(token);
|
|
465
686
|
index += 1;
|
|
466
687
|
|
|
@@ -495,29 +716,71 @@ async function parseWrapperArgs(argv, runtime = {}) {
|
|
|
495
716
|
}
|
|
496
717
|
|
|
497
718
|
const options = parsed.options || {};
|
|
719
|
+
const releaseVersion = options['release-version'] || options.version;
|
|
498
720
|
|
|
499
721
|
return {
|
|
500
722
|
passthroughArgs: split.passthroughArgs,
|
|
501
723
|
rawArgs,
|
|
502
724
|
resolveOptions: {
|
|
503
725
|
assetName: options['asset-name'],
|
|
504
|
-
autoDownload: options['auto-download'] === true,
|
|
726
|
+
autoDownload: options['auto-download'] === true || options.download === true,
|
|
505
727
|
binaryPath: options['binary-path'],
|
|
506
728
|
channel: options.channel,
|
|
729
|
+
force: options.force === true,
|
|
507
730
|
githubToken: options['github-token'],
|
|
508
731
|
repo: options.repo,
|
|
732
|
+
releaseVersion,
|
|
509
733
|
staticBuild: options['static-build'] === true,
|
|
510
734
|
targetDir: options['target-dir'],
|
|
511
735
|
verify: options.verify !== false,
|
|
512
|
-
version:
|
|
736
|
+
version: releaseVersion
|
|
513
737
|
},
|
|
514
738
|
usedDoubleDash: split.usedDoubleDash,
|
|
515
739
|
wrapperOptions: {
|
|
516
|
-
|
|
740
|
+
checkUpdate: options['check-update'] === true,
|
|
741
|
+
install: options.install === true,
|
|
742
|
+
printBinaryPath: options['print-binary-path'] === true,
|
|
743
|
+
sdkHelp: options['sdk-help'] === true,
|
|
744
|
+
upgrade: options.upgrade === true
|
|
517
745
|
}
|
|
518
746
|
};
|
|
519
747
|
}
|
|
520
748
|
|
|
749
|
+
function writeLine(stream, message) {
|
|
750
|
+
stream.write(`${message}\n`);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function formatWrapperBinaryStatus(result) {
|
|
754
|
+
if (result && Object.prototype.hasOwnProperty.call(result, 'latestVersion')) {
|
|
755
|
+
if (!result.currentVersion) {
|
|
756
|
+
return `redblue is not installed; latest available is ${result.latestVersion}`;
|
|
757
|
+
}
|
|
758
|
+
if (result.hasUpdate) {
|
|
759
|
+
return `redblue update available at ${result.binaryPath}: ${result.currentVersion} -> ${result.latestVersion}`;
|
|
760
|
+
}
|
|
761
|
+
return `redblue is up to date at ${result.binaryPath} (${result.currentVersion})`;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
if (result && Object.prototype.hasOwnProperty.call(result, 'previousVersion')) {
|
|
765
|
+
if (!result.changed) {
|
|
766
|
+
return `redblue already at ${result.binaryPath} (${result.version || 'version unknown'})`;
|
|
767
|
+
}
|
|
768
|
+
if (result.previousVersion) {
|
|
769
|
+
return `redblue upgraded at ${result.binaryPath}: ${result.previousVersion} -> ${result.version}`;
|
|
770
|
+
}
|
|
771
|
+
return `redblue installed at ${result.binaryPath} (${result.version || 'version unknown'})`;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
if (result && result.binaryPath) {
|
|
775
|
+
if (!result.changed) {
|
|
776
|
+
return `redblue already installed at ${result.binaryPath}${result.version ? ` (${result.version})` : ''}`;
|
|
777
|
+
}
|
|
778
|
+
return `redblue installed at ${result.binaryPath}${result.version ? ` (${result.version})` : ''}`;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
return 'redblue binary status unavailable';
|
|
782
|
+
}
|
|
783
|
+
|
|
521
784
|
function formatWrapperHelp() {
|
|
522
785
|
return [
|
|
523
786
|
'redblue-cli wrapper',
|
|
@@ -529,19 +792,27 @@ function formatWrapperHelp() {
|
|
|
529
792
|
'',
|
|
530
793
|
'Wrapper options:',
|
|
531
794
|
' --binary-path <path> Use an explicit redblue binary',
|
|
532
|
-
' --target-dir <dir> Resolve or
|
|
533
|
-
' --auto-download Download the binary if it is missing',
|
|
795
|
+
' --target-dir <dir> Resolve or install the managed binary in this directory',
|
|
796
|
+
' --auto-download Download the binary if it is missing before command execution',
|
|
797
|
+
' --install Ensure the managed binary is installed',
|
|
798
|
+
' --upgrade Upgrade the managed binary to the requested release',
|
|
799
|
+
' --check-update Check the installed binary against the latest release',
|
|
800
|
+
' --print-binary-path Print the resolved binary path and exit',
|
|
534
801
|
' --channel <name> Release channel for downloads (stable, latest, next)',
|
|
535
|
-
' --version <tag>
|
|
802
|
+
' --release-version <tag> Pin a release version for install or upgrade',
|
|
803
|
+
' --version <tag> Alias for --release-version',
|
|
536
804
|
' --asset-name <name> Override the release asset name',
|
|
537
805
|
' --repo <owner/name> Override the GitHub repository',
|
|
538
806
|
' --github-token <token> GitHub token for release downloads',
|
|
539
807
|
' --static-build Prefer static Linux assets when available',
|
|
808
|
+
' --force Force a reinstall when used with --upgrade',
|
|
540
809
|
' --no-verify Skip SHA256 verification on download',
|
|
541
810
|
' --sdk-help Show this wrapper help',
|
|
542
811
|
'',
|
|
543
812
|
'Notes:',
|
|
544
813
|
' Wrapper options must come before the redblue command.',
|
|
814
|
+
' Managed installs default to ~/.local/bin and still detect legacy ~/.redblue/bin installs.',
|
|
815
|
+
' Use "rb --version" to query the real redblue binary version after installation.',
|
|
545
816
|
' The exact command "npx rb" only works when a package named "rb" exists or when this package is already installed and exposes the rb bin.',
|
|
546
817
|
''
|
|
547
818
|
].join('\n');
|
|
@@ -568,13 +839,71 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
568
839
|
|
|
569
840
|
try {
|
|
570
841
|
const parsed = await parseWrapperArgs(argv, runtime);
|
|
842
|
+
const cliOptions = Object.assign({}, parsed.resolveOptions, {
|
|
843
|
+
cwd: runtime.cwd || process.cwd(),
|
|
844
|
+
env: Object.assign({}, process.env, runtime.env || {})
|
|
845
|
+
});
|
|
571
846
|
|
|
572
847
|
if (parsed.wrapperOptions.sdkHelp) {
|
|
573
|
-
stdout
|
|
848
|
+
writeLine(stdout, formatWrapperHelp());
|
|
574
849
|
return 0;
|
|
575
850
|
}
|
|
576
851
|
|
|
577
|
-
|
|
852
|
+
let resolvedInfo = null;
|
|
853
|
+
|
|
854
|
+
if (parsed.wrapperOptions.checkUpdate) {
|
|
855
|
+
const updateStatus = await checkForUpdates(cliOptions);
|
|
856
|
+
const updateMessage = formatWrapperBinaryStatus(updateStatus);
|
|
857
|
+
|
|
858
|
+
if (parsed.passthroughArgs.length === 0) {
|
|
859
|
+
writeLine(stdout, updateMessage);
|
|
860
|
+
return 0;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
writeLine(stderr, updateMessage);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
if (parsed.wrapperOptions.upgrade) {
|
|
867
|
+
const upgradeResult = await upgradeBinary(cliOptions);
|
|
868
|
+
resolvedInfo = {
|
|
869
|
+
binaryPath: upgradeResult.binaryPath,
|
|
870
|
+
source: upgradeResult.source
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
if (parsed.passthroughArgs.length === 0 && !parsed.wrapperOptions.printBinaryPath) {
|
|
874
|
+
writeLine(stdout, formatWrapperBinaryStatus(upgradeResult));
|
|
875
|
+
return 0;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
writeLine(stderr, formatWrapperBinaryStatus(upgradeResult));
|
|
879
|
+
} else if (parsed.wrapperOptions.install) {
|
|
880
|
+
const installResult = await ensureInstalled(cliOptions);
|
|
881
|
+
resolvedInfo = {
|
|
882
|
+
binaryPath: installResult.binaryPath,
|
|
883
|
+
source: installResult.source
|
|
884
|
+
};
|
|
885
|
+
|
|
886
|
+
if (parsed.passthroughArgs.length === 0 && !parsed.wrapperOptions.printBinaryPath) {
|
|
887
|
+
writeLine(stdout, formatWrapperBinaryStatus(installResult));
|
|
888
|
+
return 0;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
writeLine(stderr, formatWrapperBinaryStatus(installResult));
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
if (!resolvedInfo) {
|
|
895
|
+
resolvedInfo = await resolveBinaryWithInfo(cliOptions);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
if (parsed.wrapperOptions.printBinaryPath) {
|
|
899
|
+
if (parsed.passthroughArgs.length === 0) {
|
|
900
|
+
writeLine(stdout, resolvedInfo.binaryPath);
|
|
901
|
+
return 0;
|
|
902
|
+
}
|
|
903
|
+
writeLine(stderr, `redblue binary: ${resolvedInfo.binaryPath}`);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
const binaryPath = resolvedInfo.binaryPath;
|
|
578
907
|
/* node:coverage disable */
|
|
579
908
|
const spawnOptions = {
|
|
580
909
|
cwd: runtime.cwd || process.cwd(),
|
|
@@ -898,43 +1227,62 @@ async function createClient(options = {}) {
|
|
|
898
1227
|
}
|
|
899
1228
|
|
|
900
1229
|
module.exports = {
|
|
1230
|
+
checkForUpdates,
|
|
901
1231
|
createClient,
|
|
902
1232
|
downloadBinary,
|
|
1233
|
+
ensureInstalled,
|
|
1234
|
+
getBinaryInfo,
|
|
903
1235
|
getManifest,
|
|
1236
|
+
getInstalledVersion,
|
|
904
1237
|
runCli,
|
|
905
1238
|
resolveAssetName,
|
|
906
|
-
resolveBinary
|
|
1239
|
+
resolveBinary,
|
|
1240
|
+
upgradeBinary
|
|
907
1241
|
};
|
|
908
1242
|
|
|
909
1243
|
module.exports._internal = {
|
|
910
1244
|
attachRoute,
|
|
911
1245
|
buildInvocation,
|
|
1246
|
+
checkForUpdates,
|
|
912
1247
|
createDomainProxy,
|
|
913
1248
|
defaultInstallDir,
|
|
914
1249
|
downloadToFile,
|
|
1250
|
+
ensureInstalled,
|
|
915
1251
|
ensureObject,
|
|
916
1252
|
execFilePromise,
|
|
917
1253
|
exists,
|
|
1254
|
+
formatWrapperBinaryStatus,
|
|
918
1255
|
formatWrapperHelp,
|
|
919
1256
|
findFlag,
|
|
1257
|
+
getBinaryInfo,
|
|
920
1258
|
getParserCandidatePaths,
|
|
921
1259
|
getDefaultBinaryName,
|
|
1260
|
+
getInstalledVersion,
|
|
922
1261
|
getReleaseTag,
|
|
923
1262
|
invokeJson,
|
|
924
1263
|
invokeRaw,
|
|
925
1264
|
isExecutable,
|
|
926
1265
|
kebabToCamel,
|
|
1266
|
+
legacyInstallDir,
|
|
927
1267
|
loadCliArgsParser,
|
|
1268
|
+
normalizeReleaseTag,
|
|
928
1269
|
parseWrapperArgs,
|
|
1270
|
+
parseInstalledVersion,
|
|
929
1271
|
request,
|
|
930
1272
|
requestJson,
|
|
931
1273
|
requestText,
|
|
932
1274
|
resolveFromPath,
|
|
1275
|
+
resolveBinaryWithInfo,
|
|
1276
|
+
resolveLegacyBinaryPath,
|
|
1277
|
+
resolveManagedBinaryPath,
|
|
1278
|
+
resolveManagedUpgradeDestination,
|
|
933
1279
|
sha256File,
|
|
934
1280
|
splitWrapperArgs,
|
|
935
1281
|
spawnBinary,
|
|
936
1282
|
toImportSpecifier,
|
|
1283
|
+
upgradeBinary,
|
|
937
1284
|
waitForChild,
|
|
1285
|
+
writeLine,
|
|
938
1286
|
verifyChecksum
|
|
939
1287
|
};
|
|
940
1288
|
|