Skip to content

Commit 09346bc

Browse files
committed
feat: show bootstrap installation progress
1 parent 15e68b9 commit 09346bc

5 files changed

Lines changed: 79 additions & 7 deletions

File tree

‎docs/DISTRIBUTION.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ The release also includes `install.sh` and `install.ps1`. README downloads the
2727
installer from the same release as the application archives, keeping the
2828
bootstrap script and archive layout in sync.
2929

30+
In a terminal, the bootstrap installer highlights download, verification,
31+
extraction, and wizard startup messages. On macOS/Linux, curl shows its native
32+
download progress bar (or activity indicator when the size is unknown).
33+
PowerShell shows native progress for installation phases and web downloads,
34+
and closes its progress display before starting the wizard and on failure.
35+
Redirected output and CI use plain status lines; `NO_COLOR` disables colored
36+
status messages.
37+
3038
The stable asset names allow installers to use GitHub's
3139
`releases/latest/download` URL while the release tag records the exact version.
3240
Installations are stored by archive checksum, so installing the same release is

‎install.ps1‎

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@ param(
2020

2121
$ErrorActionPreference = "Stop"
2222

23+
$interactiveOutput = -not [Console]::IsOutputRedirected -and -not [Console]::IsErrorRedirected -and
24+
$env:TERM -ne "dumb" -and -not $env:CI
25+
26+
function Write-InstallStatus {
27+
param([string]$Message, [switch]$Progress)
28+
29+
if ($interactiveOutput -and -not $env:NO_COLOR) {
30+
Write-Host $Message -ForegroundColor Cyan
31+
} else {
32+
Write-Host $Message
33+
}
34+
if ($interactiveOutput) {
35+
if ($Progress) {
36+
Write-Progress -Id 1 -Activity "Installing Jmix CLI" -Status $Message
37+
} else {
38+
Write-Progress -Id 1 -Activity "Installing Jmix CLI" -Completed
39+
}
40+
}
41+
}
42+
2343
if ($env:OS -ne "Windows_NT") {
2444
throw "Jmix CLI installer: install.ps1 supports Windows only."
2545
}
@@ -46,11 +66,13 @@ function Copy-ReleaseAsset {
4666
[Parameter(Mandatory = $true)][string]$Destination
4767
)
4868

49-
Write-Host "Downloading $Name..."
69+
Write-InstallStatus "Downloading $Name..." -Progress
5070
if (Test-Path -LiteralPath $ReleaseBaseUrl -PathType Container) {
5171
Copy-Item -LiteralPath (Join-Path $ReleaseBaseUrl $Name) -Destination $Destination
5272
} else {
5373
$url = $ReleaseBaseUrl.TrimEnd("/") + "/" + $Name
74+
# Keep Invoke-WebRequest's own byte progress quiet in logs as well.
75+
if (-not $interactiveOutput) { $ProgressPreference = "SilentlyContinue" }
5476
Invoke-WebRequest -UseBasicParsing -Uri $url -OutFile $Destination
5577
}
5678
}
@@ -60,6 +82,7 @@ try {
6082
Copy-ReleaseAsset -Name $archiveName -Destination $archiveFile
6183
Copy-ReleaseAsset -Name $checksumName -Destination $checksumFile
6284

85+
Write-InstallStatus "Verifying $archiveName..." -Progress
6386
$checksumContent = Get-Content -LiteralPath $checksumFile -Raw
6487
if ([string]::IsNullOrWhiteSpace($checksumContent)) {
6588
throw "Jmix CLI installer: invalid checksum file for $archiveName."
@@ -89,6 +112,7 @@ try {
89112
$extractDir = Join-Path $tempDir "extracted"
90113
New-Item -ItemType Directory -Path $extractDir | Out-Null
91114
New-Item -ItemType Directory -Force -Path $versionsDir | Out-Null
115+
Write-InstallStatus "Extracting $archiveName..." -Progress
92116
Expand-Archive -LiteralPath $archiveFile -DestinationPath $extractDir
93117
$imageDir = Join-Path $extractDir "jmix"
94118
if (-not (Test-Path -LiteralPath (Join-Path $imageDir "jmix.exe") -PathType Leaf)) {
@@ -124,7 +148,7 @@ try {
124148
Set-Content -LiteralPath (Join-Path $InstallRoot "bin-dir") -Value $BinDir -Encoding UTF8
125149

126150
if ($installed) {
127-
Write-Host "Installed Jmix CLI at $commandPath"
151+
Write-InstallStatus "Installed Jmix CLI at $commandPath"
128152
}
129153

130154
if (-not $SkipPathUpdate -and $env:JMIX_CLI_SKIP_PATH_UPDATE -ne "1") {
@@ -140,6 +164,9 @@ try {
140164
$env:Path = "$BinDir;$env:Path"
141165
}
142166
} finally {
167+
if ($interactiveOutput) {
168+
Write-Progress -Id 1 -Activity "Installing Jmix CLI" -Completed
169+
}
143170
if (Test-Path -LiteralPath $tempDir) {
144171
Remove-Item -LiteralPath $tempDir -Recurse -Force
145172
}
@@ -149,5 +176,5 @@ if ($NoRun -or $env:JMIX_CLI_NO_RUN -eq "1") {
149176
return
150177
}
151178

152-
Write-Host "Starting the Jmix project wizard..."
179+
Write-InstallStatus "Starting the Jmix project wizard..."
153180
& $launcher @CliArguments

‎install.sh‎

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@ readonly RELEASE_BASE_URL="${JMIX_CLI_RELEASE_BASE_URL:-$DEFAULT_RELEASE_BASE_UR
77
readonly INSTALL_ROOT="${JMIX_CLI_INSTALL_ROOT:-${XDG_DATA_HOME:-$HOME/.local/share}/jmix-cli}"
88
readonly BIN_DIR="${JMIX_CLI_BIN_DIR:-$HOME/.local/bin}"
99

10+
interactive_output=false
11+
if [[ -t 1 && -t 2 && "${TERM:-dumb}" != "dumb" && -z "${CI:-}" ]]; then
12+
interactive_output=true
13+
fi
14+
15+
status() {
16+
local color="$1"
17+
shift
18+
if [[ "$interactive_output" == true && -z "${NO_COLOR:-}" ]]; then
19+
printf '\033[1;%sm%s\033[0m\n' "$color" "$*"
20+
else
21+
printf '%s\n' "$*"
22+
fi
23+
}
24+
1025
fail() {
1126
echo "Jmix CLI installer: $*" >&2
1227
exit 1
@@ -45,10 +60,14 @@ download_asset() {
4560
local destination="$2"
4661
local base="${RELEASE_BASE_URL%/}"
4762

48-
echo "Downloading $name..."
63+
status 36 "Downloading $name..."
4964
case "$base" in
5065
http://* | https://* | file://*)
51-
curl -fsSL "$base/$name" -o "$destination"
66+
local progress_options=(-s)
67+
if [[ "$interactive_output" == true ]]; then
68+
progress_options=(--progress-bar)
69+
fi
70+
curl -fSL "${progress_options[@]}" "$base/$name" -o "$destination"
5271
;;
5372
*)
5473
cp "$base/$name" "$destination"
@@ -61,6 +80,7 @@ checksum_file="$temp_dir/$checksum_name"
6180
download_asset "$archive_name" "$archive_file"
6281
download_asset "$checksum_name" "$checksum_file"
6382

83+
status 36 "Verifying $archive_name..."
6484
expected_checksum="$(awk 'NR == 1 { print tolower($1) }' "$checksum_file")"
6585
[[ "$expected_checksum" =~ ^[[:xdigit:]]{64}$ ]] || fail "invalid checksum file for $archive_name."
6686

@@ -98,6 +118,7 @@ else
98118
[[ ! -e "$version_dir" ]] || fail "incomplete installation found at $version_dir."
99119
extract_dir="$temp_dir/extracted"
100120
mkdir -p "$extract_dir" "$versions_dir"
121+
status 36 "Extracting $archive_name..."
101122
tar -xzf "$archive_file" -C "$extract_dir"
102123
[[ -x "$extract_dir/$image_name/$launcher_relative" ]] || fail "release archive has an unexpected layout."
103124
: > "$extract_dir/$image_name/$INSTALL_MARKER"
@@ -136,7 +157,7 @@ mkdir -p "$INSTALL_ROOT"
136157
printf '%s\n' "$BIN_DIR" > "$INSTALL_ROOT/bin-dir"
137158

138159
if [[ "$installed" == true ]]; then
139-
echo "Installed Jmix CLI at $command_path"
160+
status 32 "Installed Jmix CLI at $command_path"
140161
fi
141162
case ":$PATH:" in
142163
*":$BIN_DIR:"*) ;;
@@ -147,7 +168,7 @@ if [[ "${JMIX_CLI_NO_RUN:-0}" == "1" ]]; then
147168
exit 0
148169
fi
149170

150-
echo "Starting the Jmix project wizard..."
171+
status 36 "Starting the Jmix project wizard..."
151172
cleanup
152173
trap - EXIT HUP INT TERM
153174
if { exec 3</dev/tty; } 2>/dev/null; then

‎tests/test-install.ps1‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ try {
2626
if ($firstOutput -notmatch "Downloading $([regex]::Escape($archive.Name))\.\.\.") {
2727
throw "Installer did not report the release download."
2828
}
29+
if ($firstOutput -notmatch "Verifying $([regex]::Escape($archive.Name))" -or
30+
$firstOutput -notmatch "Extracting $([regex]::Escape($archive.Name))") {
31+
throw "Installer did not report verification and extraction."
32+
}
33+
if ($firstOutput.Contains([string][char]27)) {
34+
throw "Redirected installer output contains terminal escape sequences."
35+
}
2936

3037
$commandPath = Join-Path $binDir "jmix.cmd"
3138
if (-not (Test-Path -LiteralPath $commandPath -PathType Leaf)) {

‎tests/test-install.sh‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ run_installer() {
3737
first_output="$(run_installer "$release_dir")"
3838
[[ "$first_output" == *"Downloading $archive_name..."* ]]
3939
[[ "$first_output" == *"Installed Jmix CLI"* ]]
40+
[[ "$first_output" == *"Verifying $archive_name..."* ]]
41+
[[ "$first_output" == *"Extracting $archive_name..."* ]]
42+
[[ "$first_output" != *$'\033'* && "$first_output" != *$'\r'* ]]
4043
[[ -x "$temp_dir/bin/jmix" ]]
4144
# Self-update reads these; never let the tests reach the real release feed.
4245
export JMIX_CLI_NO_AUTO_UPDATE=1
@@ -76,6 +79,12 @@ start_output="$(
7679
[[ "$start_output" == *"Starting the Jmix project wizard"* ]]
7780
[[ "$start_output" == *"Jmix CLI"* ]]
7881

82+
# URL downloads use curl too; redirected output must stay plain and quiet.
83+
url_output="$(run_installer "file://$release_dir" 2>&1)"
84+
[[ "$url_output" == *"already up to date"* ]]
85+
[[ "$url_output" != *$'\033'* && "$url_output" != *$'\r'* ]]
86+
[[ "$url_output" != *"100.0%"* ]]
87+
7988
tampered_dir="$temp_dir/tampered-release"
8089
mkdir -p "$tampered_dir"
8190
cp "$release_dir/$archive_name" "$release_dir/$archive_name.sha256" "$tampered_dir/"

0 commit comments

Comments
 (0)