browser4-cli 4.13.17 → 4.13.19
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/bin/browser4-cli-darwin-arm64 +0 -0
- package/bin/browser4-cli-darwin-x64 +0 -0
- package/bin/browser4-cli-linux-arm64 +0 -0
- package/bin/browser4-cli-linux-musl-arm64 +0 -0
- package/bin/browser4-cli-linux-musl-x64 +0 -0
- package/bin/browser4-cli-linux-x64 +0 -0
- package/bin/browser4-cli-win32-x64.exe +0 -0
- package/package.json +1 -1
- package/scripts/README.md +20 -1
- package/scripts/install-browser4-cli.ps1 +174 -46
- package/scripts/install-browser4-cli.sh +98 -28
- package/scripts/smoke-test-runtime-bundle.sh +18 -3
- package/scripts/tests/install-browser4-cli.tests.ps1 +150 -15
- package/scripts/tests/install-browser4-cli.tests.sh +157 -10
- package/scripts/tests/wait-for-npm-version.tests.sh +219 -0
- package/scripts/wait-for-npm-version.sh +89 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/scripts/README.md
CHANGED
|
@@ -78,12 +78,13 @@ Runs a full CLI smoke test suitable for CI and local development:
|
|
|
78
78
|
./smoke-test-runtime-bundle.sh <cli-binary> <bundle-archive> [test-port] [timeout-secs]
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
###
|
|
81
|
+
### Script tests
|
|
82
82
|
|
|
83
83
|
| File | Purpose |
|
|
84
84
|
|------|---------|
|
|
85
85
|
| `tests/install-browser4-cli.tests.sh` | Unit tests for the Unix install script |
|
|
86
86
|
| `tests/install-browser4-cli.tests.ps1` | Unit tests for the Windows install script (Pester) |
|
|
87
|
+
| `tests/wait-for-npm-version.tests.sh` | Unit tests for `wait-for-npm-version.sh` (stubbed `npm`, no network) |
|
|
87
88
|
|
|
88
89
|
## Publish (npm)
|
|
89
90
|
|
|
@@ -94,6 +95,7 @@ Runs a full CLI smoke test suitable for CI and local development:
|
|
|
94
95
|
| `publish-if-needed.js` | Publishes to npm only when the local version differs from the registry. Uses `--tag next` for prerelease versions (containing `-`). |
|
|
95
96
|
| `sync-readme.mjs` | Temporarily copies the repository root `README.md` to `cli/README.md` for npm pack/publish, then restores the original CLI README in `postpack`. |
|
|
96
97
|
| `postinstall.js` | npm `postinstall` hook: downloads the platform native binary after `npm install` |
|
|
98
|
+
| `wait-for-npm-version.sh` | Waits until a published version is actually visible on npm; called by the release workflows after `npm publish` |
|
|
97
99
|
|
|
98
100
|
### Version check
|
|
99
101
|
|
|
@@ -113,6 +115,23 @@ node scripts/publish-if-needed.js --dry-run # print what would happen
|
|
|
113
115
|
|
|
114
116
|
Optional env: `BROWSER4_CLI_NPM_REMOTE_VERSION` to override the remote version for testing.
|
|
115
117
|
|
|
118
|
+
### Verifying a publish landed
|
|
119
|
+
|
|
120
|
+
`npm publish` exiting 0 only means the registry accepted the upload — npm processes
|
|
121
|
+
publishes asynchronously and answers with *"Your package is being processed and may take a
|
|
122
|
+
few minutes to become available"*, after which the version can stay invisible to
|
|
123
|
+
`npm view` for a while. `wait-for-npm-version.sh` polls until the exact version is
|
|
124
|
+
visible (10 minutes by default) and only then lets the release proceed:
|
|
125
|
+
|
|
126
|
+
```shell
|
|
127
|
+
bash scripts/wait-for-npm-version.sh browser4-cli 4.13.18 # 10 min budget, 15 s interval
|
|
128
|
+
bash scripts/wait-for-npm-version.sh browser4-cli 4.13.18 120 5 # 2 min budget, 5 s interval
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Exit code 0 = version visible; 1 = still not visible when the budget expired (the message
|
|
132
|
+
includes the last registry answer and manual re-check commands). Both `release.yml` and
|
|
133
|
+
`release-cli.yml` call it in their `Verify npm package was published` step.
|
|
134
|
+
|
|
116
135
|
### README sync for npm package
|
|
117
136
|
|
|
118
137
|
`cli/package.json` wires the README sync into npm packaging hooks:
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
|
|
51
51
|
.PARAMETER Force
|
|
52
52
|
Force reinstallation even if the binary is already installed at the target path.
|
|
53
|
-
Overrides -SkipIfInstalled
|
|
53
|
+
Overrides -SkipIfInstalled (the locked-file workaround in Set-BinaryFile is
|
|
54
|
+
always attempted, with or without this switch).
|
|
54
55
|
|
|
55
56
|
.PARAMETER SkipBackend
|
|
56
57
|
Skip installing/upgrading the Browser4 backend (runtime bundle).
|
|
@@ -115,6 +116,17 @@ param(
|
|
|
115
116
|
|
|
116
117
|
$ErrorActionPreference = "Stop"
|
|
117
118
|
|
|
119
|
+
# Windows PowerShell 5.1 on an older .NET defaults to TLS 1.0, which GitHub and
|
|
120
|
+
# the OSS mirror both refuse ("Could not create SSL/TLS secure channel"). Pin
|
|
121
|
+
# 1.2 when the runtime offers it; PowerShell 6+ already negotiates correctly.
|
|
122
|
+
if ($PSVersionTable.PSVersion.Major -lt 6) {
|
|
123
|
+
try {
|
|
124
|
+
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
|
|
125
|
+
} catch {
|
|
126
|
+
# Runtime without TLS 1.2 support -- keep its default
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
118
130
|
# ----------------------------------------------
|
|
119
131
|
# Script location -- find ourselves on disk
|
|
120
132
|
# ----------------------------------------------
|
|
@@ -280,16 +292,28 @@ function Test-ChinaLocale {
|
|
|
280
292
|
return $true
|
|
281
293
|
}
|
|
282
294
|
|
|
283
|
-
# 3 -- .NET TimeZoneInfo (works on Windows and Unix PowerShell 7+)
|
|
295
|
+
# 3 -- .NET TimeZoneInfo (works on Windows and Unix PowerShell 7+).
|
|
296
|
+
# Windows reports Windows ids ("China Standard Time"); the IANA ids only
|
|
297
|
+
# appear on Unix, so matching IANA alone made this branch dead on Windows.
|
|
284
298
|
try {
|
|
285
299
|
$tzId = [System.TimeZoneInfo]::Local.Id
|
|
286
|
-
if ($tzId -match '^Asia/(Shanghai|Chongqing|Urumqi|Harbin)$') {
|
|
300
|
+
if ($tzId -eq 'China Standard Time' -or $tzId -match '^Asia/(Shanghai|Chongqing|Urumqi|Harbin)$') {
|
|
287
301
|
return $true
|
|
288
302
|
}
|
|
289
303
|
} catch {
|
|
290
304
|
# TimeZoneInfo not available (unlikely on PS 5.1+ but guard anyway)
|
|
291
305
|
}
|
|
292
306
|
|
|
307
|
+
# 3b -- current culture: a Chinese Windows install reports zh-CN even when
|
|
308
|
+
# no locale environment variables are set.
|
|
309
|
+
try {
|
|
310
|
+
if ([System.Globalization.CultureInfo]::CurrentCulture.Name -match '^zh-(CN|Hans)') {
|
|
311
|
+
return $true
|
|
312
|
+
}
|
|
313
|
+
} catch {
|
|
314
|
+
# Culture lookup failed -- not fatal
|
|
315
|
+
}
|
|
316
|
+
|
|
293
317
|
# 4 -- /etc/timezone (PowerShell on Linux/macOS)
|
|
294
318
|
if (-not $script:OSWin -and (Test-Path '/etc/timezone')) {
|
|
295
319
|
try {
|
|
@@ -345,6 +369,43 @@ function Get-DownloadUrls {
|
|
|
345
369
|
return $urls
|
|
346
370
|
}
|
|
347
371
|
|
|
372
|
+
<#
|
|
373
|
+
.SYNOPSIS
|
|
374
|
+
Check that a downloaded file really is a native executable.
|
|
375
|
+
Magic bytes are the cheapest integrity signal that needs no network and no
|
|
376
|
+
published checksum file: an HTML error page or a truncated body that happens
|
|
377
|
+
to be larger than the size threshold is rejected here.
|
|
378
|
+
#>
|
|
379
|
+
function Test-BinaryMagic {
|
|
380
|
+
param([string]$Path)
|
|
381
|
+
|
|
382
|
+
if (-not (Test-Path $Path)) { return $false }
|
|
383
|
+
# Read exactly four bytes through .NET: works on 5.1 and 7.x alike
|
|
384
|
+
# (Get-Content -Encoding Byte is gone in PowerShell 7).
|
|
385
|
+
$bytes = New-Object byte[] 4
|
|
386
|
+
$read = 0
|
|
387
|
+
try {
|
|
388
|
+
$stream = [System.IO.File]::OpenRead($Path)
|
|
389
|
+
try {
|
|
390
|
+
$read = $stream.Read($bytes, 0, 4)
|
|
391
|
+
} finally {
|
|
392
|
+
$stream.Dispose()
|
|
393
|
+
}
|
|
394
|
+
} catch {
|
|
395
|
+
return $false
|
|
396
|
+
}
|
|
397
|
+
if ($read -lt 4) { return $false }
|
|
398
|
+
|
|
399
|
+
$magic = ($bytes | ForEach-Object { $_.ToString('x2') }) -join ''
|
|
400
|
+
|
|
401
|
+
switch -Regex ($magic) {
|
|
402
|
+
'^7f454c46' { return $true } # ELF (linux glibc / musl)
|
|
403
|
+
'^4d5a' { return $true } # PE / MZ (windows)
|
|
404
|
+
'^(feedface|feedfacf|cefaedfe|cffaedfe|cafebabe)$' { return $true } # Mach-O, incl. fat
|
|
405
|
+
default { return $false }
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
348
409
|
function Invoke-Download {
|
|
349
410
|
param([string]$Url, [string]$OutFile, [string]$Label)
|
|
350
411
|
|
|
@@ -359,12 +420,16 @@ function Invoke-Download {
|
|
|
359
420
|
try {
|
|
360
421
|
$ProgressPreference = if ($Silent) { "SilentlyContinue" } else { "Continue" }
|
|
361
422
|
|
|
362
|
-
# Use Invoke-WebRequest with progress bar
|
|
363
423
|
Invoke-WebRequest -Uri $Url -OutFile $OutFile -UseBasicParsing -ErrorAction Stop
|
|
364
424
|
|
|
365
425
|
if (Test-Path $OutFile) {
|
|
366
426
|
$size = (Get-Item $OutFile).Length
|
|
367
427
|
if ($size -gt 102400) { # > 100 KB minimum
|
|
428
|
+
if (-not (Test-BinaryMagic -Path $OutFile)) {
|
|
429
|
+
Write-WarnMsg "Downloaded file is not a native executable (bad magic bytes) -- refusing it"
|
|
430
|
+
Remove-Item $OutFile -Force -ErrorAction SilentlyContinue
|
|
431
|
+
return $false
|
|
432
|
+
}
|
|
368
433
|
Write-Check "Downloaded $( [math]::Round($size / 1MB, 1) ) MB"
|
|
369
434
|
return $true
|
|
370
435
|
} else {
|
|
@@ -586,29 +651,39 @@ function Add-DirectoryToUserPath {
|
|
|
586
651
|
|
|
587
652
|
$dirResolved = (Resolve-Path $Dir -ErrorAction SilentlyContinue).Path
|
|
588
653
|
if (-not $dirResolved) { $dirResolved = $Dir }
|
|
654
|
+
# Trailing separators would defeat the duplicate check below.
|
|
655
|
+
$dirResolved = $dirResolved.TrimEnd('\', '/')
|
|
589
656
|
|
|
590
657
|
# Read current user PATH
|
|
591
658
|
$currentUserPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User)
|
|
592
659
|
$paths = if ($currentUserPath) { $currentUserPath -split ";" | Where-Object { $_ } } else { @() }
|
|
593
660
|
|
|
594
|
-
# Check if already present
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
661
|
+
# Check if already present. Compare normalized, case-insensitively: Windows
|
|
662
|
+
# paths differ in case, a relative entry has to be resolved first, and a
|
|
663
|
+
# trailing separator is not a different directory.
|
|
664
|
+
$normalized = $paths | ForEach-Object {
|
|
665
|
+
$rp = Resolve-Path $_ -ErrorAction SilentlyContinue
|
|
666
|
+
$p = if ($rp) { $rp.Path } else { $_ }
|
|
667
|
+
$p.TrimEnd('\', '/')
|
|
668
|
+
}
|
|
669
|
+
if ($normalized | Where-Object { $_.Equals($dirResolved, [System.StringComparison]::OrdinalIgnoreCase) }) {
|
|
670
|
+
Write-Check "Already in user PATH: $dirResolved"
|
|
598
671
|
return
|
|
599
672
|
}
|
|
600
673
|
|
|
601
674
|
if ($DryRun) {
|
|
602
|
-
Write-Check "[DRY-RUN] Would add to user PATH: $
|
|
675
|
+
Write-Check "[DRY-RUN] Would add to user PATH: $dirResolved"
|
|
603
676
|
return
|
|
604
677
|
}
|
|
605
678
|
|
|
606
|
-
|
|
679
|
+
# Append the resolved absolute path: `-InstallDir .\b4` used to write a
|
|
680
|
+
# relative entry into the persistent user PATH.
|
|
681
|
+
$newPath = if ($currentUserPath) { "$currentUserPath;$dirResolved" } else { $dirResolved }
|
|
607
682
|
[System.Environment]::SetEnvironmentVariable("Path", $newPath, [System.EnvironmentVariableTarget]::User)
|
|
608
|
-
Write-Check "Added to user PATH: $
|
|
683
|
+
Write-Check "Added to user PATH: $dirResolved"
|
|
609
684
|
|
|
610
685
|
# Also update current session
|
|
611
|
-
$env:Path = "$env:Path;$
|
|
686
|
+
$env:Path = "$env:Path;$dirResolved"
|
|
612
687
|
}
|
|
613
688
|
|
|
614
689
|
# ----------------------------------------------
|
|
@@ -622,10 +697,16 @@ function Add-DirectoryToUserPath {
|
|
|
622
697
|
#>
|
|
623
698
|
function Get-BackendAction {
|
|
624
699
|
param([string]$StatusOutput)
|
|
625
|
-
|
|
700
|
+
# Only a status that positively reports an installed bundle means upgrade.
|
|
701
|
+
# An empty status (no CLI yet, or `status` itself failed) must not turn a
|
|
702
|
+
# fresh machine into an `upgrade`.
|
|
703
|
+
if ($StatusOutput -match 'Installed bundle:\s*not installed') {
|
|
626
704
|
return "install"
|
|
627
705
|
}
|
|
628
|
-
|
|
706
|
+
if ($StatusOutput -match 'Installed bundle:') {
|
|
707
|
+
return "upgrade"
|
|
708
|
+
}
|
|
709
|
+
return "install"
|
|
629
710
|
}
|
|
630
711
|
|
|
631
712
|
<#
|
|
@@ -635,28 +716,34 @@ function Get-BackendAction {
|
|
|
635
716
|
- no backend installed yet -> browser4-cli install
|
|
636
717
|
- backend already present -> browser4-cli upgrade (to the latest)
|
|
637
718
|
Passes -Version through as --tag so the backend matches the CLI version.
|
|
638
|
-
|
|
719
|
+
Returns $true when the backend is in place (or was skipped on request) and
|
|
720
|
+
$false when the step failed -- the caller turns that into the exit code, so a
|
|
721
|
+
broken backend is visible to scripts even though the CLI stays usable.
|
|
639
722
|
#>
|
|
640
723
|
function Install-Backend {
|
|
641
724
|
param([string]$CliPath, [string]$Tag)
|
|
642
725
|
|
|
643
726
|
if ($SkipBackend) {
|
|
644
727
|
Write-Step "Skipping backend install/upgrade (-SkipBackend)"
|
|
645
|
-
return
|
|
728
|
+
return $true
|
|
646
729
|
}
|
|
647
730
|
|
|
648
731
|
Write-Step "Checking for an existing Browser4 backend..."
|
|
649
732
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
# Binary missing or not runnable yet (e.g. --dry-run) -- fall through.
|
|
733
|
+
# -DryRun must not touch the installed CLI at all: ask what would happen
|
|
734
|
+
# instead of running `status`.
|
|
735
|
+
$action = "install"
|
|
736
|
+
if (-not $DryRun) {
|
|
655
737
|
$statusOutput = ""
|
|
738
|
+
try {
|
|
739
|
+
$statusOutput = (& $CliPath status 2>&1 | Out-String)
|
|
740
|
+
} catch {
|
|
741
|
+
# Binary missing or not runnable -- treat as "no backend yet".
|
|
742
|
+
$statusOutput = ""
|
|
743
|
+
}
|
|
744
|
+
$action = Get-BackendAction -StatusOutput $statusOutput
|
|
656
745
|
}
|
|
657
746
|
|
|
658
|
-
$action = Get-BackendAction -StatusOutput $statusOutput
|
|
659
|
-
|
|
660
747
|
$backendArgs = @($action)
|
|
661
748
|
if ($Tag) { $backendArgs += @('--tag', $Tag) }
|
|
662
749
|
|
|
@@ -668,9 +755,10 @@ function Install-Backend {
|
|
|
668
755
|
|
|
669
756
|
if ($DryRun) {
|
|
670
757
|
Write-Check "[DRY-RUN] Would run: $CliPath $($backendArgs -join ' ')"
|
|
671
|
-
return
|
|
758
|
+
return $true
|
|
672
759
|
}
|
|
673
760
|
|
|
761
|
+
$backendOk = $false
|
|
674
762
|
if ($Silent) {
|
|
675
763
|
$backendOutput = ""
|
|
676
764
|
try {
|
|
@@ -678,7 +766,8 @@ function Install-Backend {
|
|
|
678
766
|
} catch {
|
|
679
767
|
$backendOutput = $_.Exception.Message
|
|
680
768
|
}
|
|
681
|
-
|
|
769
|
+
$backendOk = ($LASTEXITCODE -eq 0)
|
|
770
|
+
if ($backendOk) {
|
|
682
771
|
Write-Check "Backend $action succeeded ($($backendArgs -join ' '))."
|
|
683
772
|
} else {
|
|
684
773
|
Write-WarnMsg "Backend $action failed ($($backendArgs -join ' ')). Retry with: browser4-cli $($backendArgs -join ' ')"
|
|
@@ -686,12 +775,15 @@ function Install-Backend {
|
|
|
686
775
|
}
|
|
687
776
|
} else {
|
|
688
777
|
& $CliPath @backendArgs
|
|
689
|
-
|
|
778
|
+
$backendOk = ($LASTEXITCODE -eq 0)
|
|
779
|
+
if ($backendOk) {
|
|
690
780
|
Write-Check "Backend $action succeeded ($($backendArgs -join ' '))."
|
|
691
781
|
} else {
|
|
692
782
|
Write-WarnMsg "Backend $action failed ($($backendArgs -join ' ')). Retry with: browser4-cli $($backendArgs -join ' ')"
|
|
693
783
|
}
|
|
694
784
|
}
|
|
785
|
+
|
|
786
|
+
return $backendOk
|
|
695
787
|
}
|
|
696
788
|
|
|
697
789
|
# ----------------------------------------------
|
|
@@ -704,6 +796,19 @@ function Main {
|
|
|
704
796
|
Write-Summary "==========================================" -Color Cyan
|
|
705
797
|
Write-Summary ""
|
|
706
798
|
|
|
799
|
+
# Validate -Version before it is interpolated into a download URL: a value
|
|
800
|
+
# like '../../evil' used to produce a valid-looking URL and also reached
|
|
801
|
+
# `--tag`. A bare semver gets the 'v' prefix, as in the Unix installer.
|
|
802
|
+
if ($Version) {
|
|
803
|
+
if ($Version -notmatch '^[A-Za-z0-9][A-Za-z0-9._-]*$') {
|
|
804
|
+
throw "-Version must be a release tag such as v4.13.18 (got '$Version')"
|
|
805
|
+
}
|
|
806
|
+
if ($Version -match '^[0-9]+\.[0-9]+\.[0-9]+') {
|
|
807
|
+
Write-Step "Using release tag 'v$Version' (release tags are prefixed with 'v')"
|
|
808
|
+
$Version = "v$Version"
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
707
812
|
# Auto-detect China mainland locale when no explicit source is given
|
|
708
813
|
if (-not $Source) {
|
|
709
814
|
$script:ChinaDetected = Test-ChinaLocale
|
|
@@ -723,7 +828,7 @@ function Main {
|
|
|
723
828
|
Write-Step "Script dir: $ScriptDir"
|
|
724
829
|
Write-Step "Platform key: $platformKey"
|
|
725
830
|
Write-Step "Binary name: $binaryName"
|
|
726
|
-
Write-Step "Default install: $(Get-DefaultInstallDir)"
|
|
831
|
+
Write-Step "Default install: $(if ($InstallDir) { $InstallDir } else { Get-DefaultInstallDir })"
|
|
727
832
|
Write-Step "China locale: $script:ChinaDetected"
|
|
728
833
|
Write-Step "Source override: $(if ($Source) { $Source } else { 'auto' })"
|
|
729
834
|
Write-Step "OS: $(if ($script:OSWin) { 'Windows' } elseif ($script:OSMac) { 'macOS' } elseif ($script:OSLinux) { 'Linux' } else { 'Unknown' })"
|
|
@@ -810,18 +915,20 @@ function Main {
|
|
|
810
915
|
}
|
|
811
916
|
|
|
812
917
|
$downloaded = $false
|
|
918
|
+
# The temp file is always cleaned up, including on -DryRun (where the
|
|
919
|
+
# download never consumes it) and on the failure path.
|
|
813
920
|
$tempFile = [System.IO.Path]::GetTempFileName()
|
|
814
921
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
$
|
|
818
|
-
|
|
922
|
+
try {
|
|
923
|
+
foreach ($entry in $urls) {
|
|
924
|
+
if (Invoke-Download -Url $entry.Url -OutFile $tempFile -Label $entry.Label) {
|
|
925
|
+
$downloaded = $true
|
|
926
|
+
break
|
|
927
|
+
}
|
|
819
928
|
}
|
|
820
|
-
}
|
|
821
929
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
throw @"
|
|
930
|
+
if (-not $downloaded) {
|
|
931
|
+
throw @"
|
|
825
932
|
Could not download browser4-cli binary.
|
|
826
933
|
|
|
827
934
|
Tried:
|
|
@@ -833,13 +940,16 @@ Please check:
|
|
|
833
940
|
- For GitHub rate limits, set GITHUB_TOKEN environment variable
|
|
834
941
|
- If you have a local copy, place it alongside this script and re-run
|
|
835
942
|
"@
|
|
836
|
-
|
|
943
|
+
}
|
|
837
944
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
945
|
+
# Move from temp to install dir
|
|
946
|
+
if (-not $DryRun) {
|
|
947
|
+
Set-BinaryFile -TargetPath $binaryPath -SourcePath $tempFile -Move
|
|
948
|
+
}
|
|
949
|
+
Write-Check "Installed: $binaryPath"
|
|
950
|
+
} finally {
|
|
951
|
+
if (Test-Path $tempFile) { Remove-Item $tempFile -Force -ErrorAction SilentlyContinue }
|
|
841
952
|
}
|
|
842
|
-
Write-Check "Installed: $binaryPath"
|
|
843
953
|
}
|
|
844
954
|
|
|
845
955
|
# On Unix, ensure executable bit
|
|
@@ -875,16 +985,28 @@ Please check:
|
|
|
875
985
|
}
|
|
876
986
|
}
|
|
877
987
|
|
|
878
|
-
# Verify
|
|
988
|
+
# Verify. A binary that cannot report its version is a failed install --
|
|
989
|
+
# report it red and exit non-zero instead of printing a green success line.
|
|
879
990
|
Write-Summary ""
|
|
991
|
+
$script:ExitCode = 0
|
|
880
992
|
if (-not $DryRun) {
|
|
993
|
+
$versionOutput = ""
|
|
994
|
+
$versionOk = $false
|
|
881
995
|
try {
|
|
882
|
-
$versionOutput = & $binaryPath --version 2>&1
|
|
996
|
+
$versionOutput = (& $binaryPath --version 2>&1 | Out-String).Trim()
|
|
997
|
+
$versionOk = ($LASTEXITCODE -eq 0) -and ($versionOutput -match '\d')
|
|
998
|
+
} catch {
|
|
999
|
+
$versionOk = $false
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
if ($versionOk) {
|
|
883
1003
|
Write-Summary "[v] browser4-cli installed successfully" -Color Green
|
|
884
1004
|
Write-Summary " Version: $versionOutput"
|
|
885
|
-
}
|
|
886
|
-
Write-Summary "[
|
|
887
|
-
Write-
|
|
1005
|
+
} else {
|
|
1006
|
+
Write-Summary "[x] Installed $binaryPath but it cannot run:" -Color Red
|
|
1007
|
+
Write-Summary " $versionOutput"
|
|
1008
|
+
Write-WarnMsg "The binary may be corrupt or built for a different platform. Delete it and re-run the installer."
|
|
1009
|
+
$script:ExitCode = 1
|
|
888
1010
|
}
|
|
889
1011
|
} else {
|
|
890
1012
|
Write-Summary "[DRY-RUN] Installation plan complete" -Color Yellow
|
|
@@ -893,8 +1015,12 @@ Please check:
|
|
|
893
1015
|
# Install / upgrade the Browser4 backend (runtime bundle) using the CLI
|
|
894
1016
|
# binary we just installed. Fresh machines get `browser4-cli install`;
|
|
895
1017
|
# machines that already have a backend get `browser4-cli upgrade`.
|
|
1018
|
+
# A backend failure keeps the CLI usable but must be visible to scripts
|
|
1019
|
+
# and CI, so it is reflected in the exit code.
|
|
896
1020
|
Write-Summary ""
|
|
897
|
-
Install-Backend -CliPath $binaryPath -Tag $Version
|
|
1021
|
+
if ((Install-Backend -CliPath $binaryPath -Tag $Version) -eq $false) {
|
|
1022
|
+
$script:ExitCode = 1
|
|
1023
|
+
}
|
|
898
1024
|
|
|
899
1025
|
Write-Summary ""
|
|
900
1026
|
Write-Summary "Run 'browser4-cli --help' to get started." -Color Cyan
|
|
@@ -903,6 +1029,8 @@ Please check:
|
|
|
903
1029
|
Write-Summary "If the command isn't found, restart your terminal or run:"
|
|
904
1030
|
Write-Summary " `$env:Path = [System.Environment]::GetEnvironmentVariable('Path','User') + ';' + [System.Environment]::GetEnvironmentVariable('Path','Machine')"
|
|
905
1031
|
}
|
|
1032
|
+
|
|
1033
|
+
exit $script:ExitCode
|
|
906
1034
|
}
|
|
907
1035
|
|
|
908
1036
|
Main
|