Skip to content

Commit 7454500

Browse files
committed
Add progress spinners and enhanced error handling to installation scripts
- we sometimes see cli commands outputing animtated glyphs that then turn into checkmarks. is it possible to do something like here? - move spinner and checkmarks to the beginning of the line - remove this line [Pasted text] - when cancelling installation, the spinner persist, glithing the terminal
1 parent aaedd43 commit 7454500

2 files changed

Lines changed: 183 additions & 23 deletions

File tree

‎install.ps1‎

Lines changed: 108 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,59 @@ if ($autoChoice) {
106106
}
107107
}
108108

109-
Write-Host "`nFetching latest version info..."
109+
$global:activeSpinner = $null
110+
111+
function Start-Spinner {
112+
param([string]$Message)
113+
Write-Host -NoNewline " $Message"
114+
try { [Console]::CursorVisible = $false } catch {}
115+
116+
$runspace = [runspacefactory]::CreateRunspace()
117+
$runspace.Open()
118+
$ps = [powershell]::Create()
119+
$ps.Runspace = $runspace
120+
$ps.AddScript({
121+
$spinner = @('-', '\', '|', '/')
122+
$i = 0
123+
while ($true) {
124+
try { [Console]::Write("`r$($spinner[$i % 4])") } catch {}
125+
$i++
126+
Start-Sleep -Milliseconds 100
127+
}
128+
}) | Out-Null
129+
$asyncResult = $ps.BeginInvoke()
130+
$spinnerObj = @{ PS = $ps; Runspace = $runspace; Message = $Message }
131+
$global:activeSpinner = $spinnerObj
132+
return $spinnerObj
133+
}
134+
135+
function Stop-Spinner {
136+
param($spinnerObj, [bool]$Success = $true)
137+
if ($global:activeSpinner -and $spinnerObj -and $global:activeSpinner.PS -eq $spinnerObj.PS) {
138+
$global:activeSpinner = $null
139+
}
140+
$msg = if ($spinnerObj.Message) { $spinnerObj.Message } else { "" }
141+
if ($spinnerObj) {
142+
try { $spinnerObj.PS.Stop() } catch {}
143+
try { $spinnerObj.PS.Dispose() } catch {}
144+
try { $spinnerObj.Runspace.Close() } catch {}
145+
try { $spinnerObj.Runspace.Dispose() } catch {}
146+
}
147+
try { [Console]::CursorVisible = $true } catch {}
148+
149+
if ($Success) {
150+
Write-Host "`r$([char]0x2714) " -ForegroundColor Green -NoNewline
151+
Write-Host $msg
152+
} else {
153+
Write-Host "`r$([char]0x2718) " -ForegroundColor Red -NoNewline
154+
Write-Host $msg
155+
}
156+
}
157+
158+
Write-Host ""
159+
160+
try {
161+
110162
$page = 1
111163
$latestTag = $null
112164

@@ -130,18 +182,30 @@ if (!$latestTag) {
130182
exit 1
131183
}
132184

133-
Write-Host "The latest is $($latestTag.name -replace '-vscode$','')"
134185
$zipUrl = $latestTag.zipball_url
135186

136187
$tmpDir = Join-Path $env:TEMP ("CWC_Install_" + [Guid]::NewGuid().ToString().Substring(0,8))
137188
New-Item -ItemType Directory -Path $tmpDir | Out-Null
138189

139190
$zipPath = Join-Path $tmpDir "source.zip"
140-
Write-Host "Downloading source code..."
141-
Invoke-WebRequest -Uri $zipUrl -OutFile $zipPath -UseBasicParsing
191+
$spinner = Start-Spinner "Downloading source code..."
192+
try {
193+
Invoke-WebRequest -Uri $zipUrl -OutFile $zipPath -UseBasicParsing
194+
Stop-Spinner $spinner $true
195+
} catch {
196+
Stop-Spinner $spinner $false
197+
Write-Host "Error: Download failed." -ForegroundColor Red
198+
Pause
199+
exit 1
200+
}
142201

143-
Write-Host "Extracting archive..."
144-
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
202+
try {
203+
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
204+
} catch {
205+
Write-Host "Error: Extraction failed." -ForegroundColor Red
206+
Pause
207+
exit 1
208+
}
145209

146210
$extractedDir = Get-ChildItem -Path $tmpDir -Directory | Select-Object -First 1
147211

@@ -153,14 +217,31 @@ if (!$extractedDir) {
153217

154218
Push-Location $extractedDir.FullName
155219

156-
Write-Host "Installing dependencies..."
220+
$spinner = Start-Spinner "Installing dependencies..."
157221
$ErrorActionPreference = "Continue"
158222
npx.cmd --yes pnpm install *>$null
223+
$cmdSuccess = $?
224+
Stop-Spinner $spinner $cmdSuccess
159225

160-
Write-Host "Building extension..."
226+
if (!$cmdSuccess) {
227+
Write-Host "Error: Failed to install dependencies." -ForegroundColor Red
228+
Pause
229+
exit 1
230+
}
231+
232+
$spinner = Start-Spinner "Building extension..."
161233
Set-Location apps/editor
162234
npx.cmd --yes pnpm run build *>$null
235+
$cmdSuccess = $?
163236
$ErrorActionPreference = "Stop"
237+
Stop-Spinner $spinner $cmdSuccess
238+
239+
if (!$cmdSuccess) {
240+
Write-Host "Error: Build failed." -ForegroundColor Red
241+
Pop-Location
242+
Pause
243+
exit 1
244+
}
164245

165246
$vsixFile = Get-ChildItem *.vsix | Select-Object -First 1
166247

@@ -174,14 +255,23 @@ if (!$vsixFile) {
174255
function Install-ToEditor($idx) {
175256
$editorName = $availableEditors[$idx]
176257
$editorCmd = $editorCmds[$idx]
258+
259+
$spinner = Start-Spinner "Installing to $editorName..."
177260
$ErrorActionPreference = "Continue"
178261
& $editorCmd --install-extension $vsixFile.FullName --force *>$null
262+
$cmdSuccess = $?
179263
$ErrorActionPreference = "Stop"
180264

181-
if ($targetScheme) {
182-
Write-Host "Updated successfully! Please reload the window or restart the editor for changes to take effect."
265+
Stop-Spinner $spinner $cmdSuccess
266+
267+
if ($cmdSuccess) {
268+
if ($targetScheme) {
269+
Write-Host "Updated successfully! Please reload the window or restart the editor for changes to take effect."
270+
} else {
271+
Write-Host "Successfully installed to $editorName!"
272+
}
183273
} else {
184-
Write-Host "Successfully installed to $editorName!"
274+
Write-Host "Error: Failed to install to $editorName." -ForegroundColor Red
185275
}
186276
}
187277

@@ -194,6 +284,13 @@ if ($choice -eq 'a' -or $choice -eq 'A') {
194284
Install-ToEditor ([int]$choice - 1)
195285
}
196286

287+
} finally {
288+
if ($global:activeSpinner) {
289+
Stop-Spinner $global:activeSpinner $false
290+
}
291+
try { [Console]::CursorVisible = $true } catch {}
292+
}
293+
197294
Pause
198295
Pop-Location
199296
Start-Process -FilePath "cmd.exe" -ArgumentList "/c", "rmdir", "/s", "/q", "`"$tmpDir`"" -WindowStyle Hidden

‎install.sh‎

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,44 @@ else
122122
fi
123123

124124
TMP_DIR=$(mktemp -d)
125-
trap '( rm -rf "$TMP_DIR" >/dev/null 2>&1 & )' EXIT
125+
126+
cleanup() {
127+
if [ -n "${SPINNER_PID:-}" ]; then
128+
kill "$SPINNER_PID" >/dev/null 2>&1 || true
129+
wait "$SPINNER_PID" 2>/dev/null || true
130+
fi
131+
tput cnorm 2>/dev/null || true
132+
rm -rf "$TMP_DIR" >/dev/null 2>&1
133+
}
134+
trap cleanup EXIT INT TERM
135+
136+
start_spinner() {
137+
tput civis 2>/dev/null || true
138+
local delay=0.1
139+
local spinstr='|/-\'
140+
while :; do
141+
local temp=${spinstr#?}
142+
printf "\r%c" "$spinstr"
143+
local spinstr=$temp${spinstr%"$temp"}
144+
sleep $delay
145+
done
146+
}
147+
148+
stop_spinner() {
149+
local pid=$1
150+
local exit_code=$2
151+
SPINNER_PID=""
152+
kill "$pid" >/dev/null 2>&1 || true
153+
wait "$pid" 2>/dev/null || true
154+
tput cnorm 2>/dev/null || true
155+
if [ "$exit_code" -eq 0 ]; then
156+
printf "\r\033[32m\xE2\x9C\x94\033[0m\n"
157+
else
158+
printf "\r\033[31m\xE2\x9C\x98\033[0m\n"
159+
fi
160+
}
126161

127162
echo ""
128-
echo "Fetching latest version info..."
129163
PAGE=1
130164
ZIP_URL=""
131165

@@ -151,12 +185,18 @@ if [ -z "$ZIP_URL" ]; then
151185
exit 1
152186
fi
153187

154-
echo "The latest is ${TAG_NAME%-vscode}"
155-
echo "Downloading source code..."
156-
curl -sL "$ZIP_URL" -o "$TMP_DIR/source.zip"
188+
printf " Downloading source code..."
189+
start_spinner &
190+
SPINNER_PID=$!
191+
if ! curl -sL "$ZIP_URL" -o "$TMP_DIR/source.zip"; then
192+
stop_spinner $SPINNER_PID 1
193+
exit 1
194+
fi
195+
stop_spinner $SPINNER_PID 0
157196

158-
echo "Extracting archive..."
159-
unzip -q "$TMP_DIR/source.zip" -d "$TMP_DIR"
197+
if ! unzip -q "$TMP_DIR/source.zip" -d "$TMP_DIR"; then
198+
exit 1
199+
fi
160200

161201
EXTRACTED_DIR=$(find "$TMP_DIR" -mindepth 1 -maxdepth 1 -type d | head -n 1)
162202

@@ -167,12 +207,24 @@ fi
167207

168208
cd "$EXTRACTED_DIR"
169209

170-
echo "Installing dependencies..."
171-
npx --yes pnpm install > /dev/null 2>&1
210+
printf " Installing dependencies..."
211+
start_spinner &
212+
SPINNER_PID=$!
213+
if ! npx --yes pnpm install > /dev/null 2>&1; then
214+
stop_spinner $SPINNER_PID 1
215+
exit 1
216+
fi
217+
stop_spinner $SPINNER_PID 0
172218

173-
echo "Building extension..."
219+
printf " Building extension..."
220+
start_spinner &
221+
SPINNER_PID=$!
174222
cd apps/editor
175-
npx --yes pnpm run build > /dev/null 2>&1
223+
if ! npx --yes pnpm run build > /dev/null 2>&1; then
224+
stop_spinner $SPINNER_PID 1
225+
exit 1
226+
fi
227+
stop_spinner $SPINNER_PID 0
176228

177229
VSIX_FILE=$(ls *.vsix | head -n 1)
178230

@@ -185,7 +237,18 @@ install_to_editor() {
185237
local idx=$1
186238
local editor_name="${AVAILABLE_EDITORS[$idx]}"
187239
local editor_cmd="${EDITOR_CMDS[$idx]}"
188-
$editor_cmd --install-extension "$VSIX_FILE" --force > /dev/null 2>&1
240+
241+
printf " Installing to %s..." "$editor_name"
242+
start_spinner &
243+
SPINNER_PID=$!
244+
245+
if ! $editor_cmd --install-extension "$VSIX_FILE" --force > /dev/null 2>&1; then
246+
stop_spinner $SPINNER_PID 1
247+
echo "Error: Failed to install to $editor_name."
248+
return 1
249+
fi
250+
251+
stop_spinner $SPINNER_PID 0
189252

190253
if [ -n "$TARGET_SCHEME" ]; then
191254
echo "Updated successfully! Please reload the window or restart the editor for changes to take effect."

0 commit comments

Comments
 (0)