weehong zrewidował ten Gist 2 weeks ago. Przejdź do rewizji
1 file changed, 20 insertions
typescript_react.json(stworzono plik)
| @@ -0,0 +1,20 @@ | |||
| 1 | + | { | |
| 2 | + | "recommendations": [ | |
| 3 | + | "dsznajder.es7-react-js-snippets", | |
| 4 | + | "planbcoding.vscode-react-refactor", | |
| 5 | + | "bradlc.vscode-tailwindcss", | |
| 6 | + | "WallabyJs.console-ninja", | |
| 7 | + | "ms-vscode.vscode-typescript-next", | |
| 8 | + | "yoavbls.pretty-ts-errors", | |
| 9 | + | "christian-kohler.path-intellisense", | |
| 10 | + | "christian-kohler.npm-intellisense", | |
| 11 | + | "dbaeumer.vscode-eslint", | |
| 12 | + | "esbenp.prettier-vscode", | |
| 13 | + | "usernamehw.errorlens", | |
| 14 | + | "eamodio.gitlens", | |
| 15 | + | "rangav.vscode-thunder-client", | |
| 16 | + | "formulahendry.auto-rename-tag", | |
| 17 | + | "GitHub.copilot", | |
| 18 | + | "Codeium.codeium" | |
| 19 | + | ] | |
| 20 | + | } | |
weehong zrewidował ten Gist 3 weeks ago. Przejdź do rewizji
Brak zmian
weehong zrewidował ten Gist 3 weeks ago. Przejdź do rewizji
1 file changed, 1 insertion, 1 deletion
install-jetbrains.sh
| @@ -29,7 +29,7 @@ readonly PLUGIN_CATALOG=( | |||
| 29 | 29 | "izhangzhihao.rainbow.brackets|Rainbow Brackets" | |
| 30 | 30 | "IdeaVIM|IdeaVim" | |
| 31 | 31 | "org.sonarlint.idea|SonarQube for IDE (SonarLint)" | |
| 32 | - | "'Key Promoter X'|Key Promoter X" | |
| 32 | + | "Key Promoter X|Key Promoter X" | |
| 33 | 33 | "net.ashald.envfile|EnvFile" | |
| 34 | 34 | "org.intellij.qodana|Qodana" | |
| 35 | 35 | ) | |
weehong zrewidował ten Gist 3 weeks ago. Przejdź do rewizji
1 file changed, 1 insertion, 1 deletion
install-jetbrains.sh
| @@ -29,7 +29,7 @@ readonly PLUGIN_CATALOG=( | |||
| 29 | 29 | "izhangzhihao.rainbow.brackets|Rainbow Brackets" | |
| 30 | 30 | "IdeaVIM|IdeaVim" | |
| 31 | 31 | "org.sonarlint.idea|SonarQube for IDE (SonarLint)" | |
| 32 | - | "9792|Key Promoter X" | |
| 32 | + | "'Key Promoter X'|Key Promoter X" | |
| 33 | 33 | "net.ashald.envfile|EnvFile" | |
| 34 | 34 | "org.intellij.qodana|Qodana" | |
| 35 | 35 | ) | |
weehong zrewidował ten Gist 3 weeks ago. Przejdź do rewizji
1 file changed, 2 insertions, 2 deletions
install-jetbrains.sh
| @@ -500,7 +500,7 @@ handle_single_instance_abort() { | |||
| 500 | 500 | shift 2 | |
| 501 | 501 | echo | |
| 502 | 502 | echo " ! '${ide_label}' is still running. Skipping remaining plugins for this IDE." >&2 | |
| 503 | - | echo " ! Close the IDE and re-run the script to finish." >&2 | |
| 503 | + | echo " ! Close the IDE and re-run the script to finish." >&2 | |
| 504 | 504 | # Mark current and remaining-for-this-IDE plugins as failed. | |
| 505 | 505 | local mark_from=0 p | |
| 506 | 506 | for p in "${SELECTED_PLUGIN_IDS[@]}"; do | |
| @@ -520,7 +520,7 @@ for ide_label in "${SELECTED_IDES[@]}"; do | |||
| 520 | 520 | ide_aborted=0 | |
| 521 | 521 | for pid in "${SELECTED_PLUGIN_IDS[@]}"; do | |
| 522 | 522 | (( ide_aborted )) && break | |
| 523 | - | printf ' %-34s ' "$pid" | |
| 523 | + | printf ' %-34s ' "$pid" | |
| 524 | 524 | rc=0 | |
| 525 | 525 | case "$itype" in | |
| 526 | 526 | ide|remotedev) | |
weehong zrewidował ten Gist 1 month ago. Przejdź do rewizji
Brak zmian
weehong zrewidował ten Gist 1 month ago. Przejdź do rewizji
Brak zmian
weehong zrewidował ten Gist 1 month ago. Przejdź do rewizji
1 file changed, 66 insertions, 20 deletions
install-jetbrains.sh
| @@ -9,8 +9,9 @@ | |||
| 9 | 9 | # | |
| 10 | 10 | # Picker UX: | |
| 11 | 11 | # - Uses fzf with --multi when fzf is on PATH (TAB to toggle, Enter to confirm). | |
| 12 | - | # - Otherwise prints a numbered list and accepts comma-separated indexes | |
| 13 | - | # (e.g. "1,3,5") or "a" for all. | |
| 12 | + | # - Otherwise prints a numbered list and accepts space-separated indexes | |
| 13 | + | # (e.g. "1 3 5"), exclusions (e.g. "!1 !4" to select all except 1 and 4), | |
| 14 | + | # or "a" for all. | |
| 14 | 15 | # | |
| 15 | 16 | # Usage: | |
| 16 | 17 | # ./install-jetbrains.sh # interactive | |
| @@ -28,7 +29,7 @@ readonly PLUGIN_CATALOG=( | |||
| 28 | 29 | "izhangzhihao.rainbow.brackets|Rainbow Brackets" | |
| 29 | 30 | "IdeaVIM|IdeaVim" | |
| 30 | 31 | "org.sonarlint.idea|SonarQube for IDE (SonarLint)" | |
| 31 | - | "Key Promoter X|Key Promoter X" | |
| 32 | + | "9792|Key Promoter X" | |
| 32 | 33 | "net.ashald.envfile|EnvFile" | |
| 33 | 34 | "org.intellij.qodana|Qodana" | |
| 34 | 35 | ) | |
| @@ -260,7 +261,7 @@ if [[ ${#CANDIDATES[@]} -eq 0 ]]; then | |||
| 260 | 261 | fi | |
| 261 | 262 | ||
| 262 | 263 | # ------------------------------------------------------------------ | |
| 263 | - | # Multi-select picker | |
| 264 | + | # Multi-select picker (Handles Space separation & Exclusions via !) | |
| 264 | 265 | # Reads newline-separated options on stdin, prints selected lines on stdout. | |
| 265 | 266 | # ------------------------------------------------------------------ | |
| 266 | 267 | pick_multi() { | |
| @@ -270,7 +271,7 @@ pick_multi() { | |||
| 270 | 271 | return | |
| 271 | 272 | fi | |
| 272 | 273 | ||
| 273 | - | # Fallback: numbered list + comma-input. | |
| 274 | + | # Fallback: numbered list + space-separated input with exclusion support. | |
| 274 | 275 | local -a items=() | |
| 275 | 276 | local line | |
| 276 | 277 | while IFS= read -r line; do items+=("$line"); done | |
| @@ -282,7 +283,7 @@ pick_multi() { | |||
| 282 | 283 | for (( i=0; i<total; i++ )); do | |
| 283 | 284 | printf ' %2d) %s\n' "$((i+1))" "${items[i]}" | |
| 284 | 285 | done | |
| 285 | - | printf '%s' "$prompt (e.g. 1,3,5 or a for all): " | |
| 286 | + | printf '%s' "$prompt (e.g. 1 3, !2 to exclude 2, or a for all): " | |
| 286 | 287 | } >&2 | |
| 287 | 288 | ||
| 288 | 289 | local input | |
| @@ -295,18 +296,63 @@ pick_multi() { | |||
| 295 | 296 | printf '%s\n' "${items[@]}" | |
| 296 | 297 | return | |
| 297 | 298 | fi | |
| 298 | - | [[ -z "$input" ]] && { echo " please enter at least one number, or 'a'." >&2; continue; } | |
| 299 | - | ||
| 300 | - | local -a picked=() bad=0 | |
| 301 | - | local tok | |
| 302 | - | IFS=',' read -r -a toks <<<"$input" | |
| 303 | - | for tok in "${toks[@]}"; do | |
| 304 | - | tok="${tok// /}" | |
| 305 | - | [[ -z "$tok" ]] && continue | |
| 306 | - | if [[ ! "$tok" =~ ^[0-9]+$ ]]; then bad=1; break; fi | |
| 307 | - | if (( tok < 1 || tok > total )); then bad=1; break; fi | |
| 308 | - | picked+=("${items[tok-1]}") | |
| 299 | + | [[ -z "$input" ]] && { echo " please enter at least one number, an exclusion, or 'a'." >&2; continue; } | |
| 300 | + | ||
| 301 | + | local -a toks=() | |
| 302 | + | IFS=' ' read -r -a toks <<<"$input" | |
| 303 | + | ||
| 304 | + | # Determine if this is an exclusion request (checks if any token starts with !) | |
| 305 | + | local is_exclusion=0 | |
| 306 | + | local t | |
| 307 | + | for t in "${toks[@]}"; do | |
| 308 | + | if [[ "$t" =~ ^\! ]]; then | |
| 309 | + | is_exclusion=1 | |
| 310 | + | break | |
| 311 | + | fi | |
| 309 | 312 | done | |
| 313 | + | ||
| 314 | + | local -a picked=() | |
| 315 | + | local bad=0 | |
| 316 | + | ||
| 317 | + | if (( is_exclusion )); then | |
| 318 | + | # Track which indices are explicitly excluded using an associative array map | |
| 319 | + | local -A excluded_map=() | |
| 320 | + | ||
| 321 | + | for t in "${toks[@]}"; do | |
| 322 | + | [[ -z "$t" ]] && continue | |
| 323 | + | if [[ ! "$t" =~ ^\![0-9]+$ ]]; then | |
| 324 | + | echo " Error: When using exclusions, all items must start with '!' (e.g., !1 !3)" >&2 | |
| 325 | + | bad=1 | |
| 326 | + | break | |
| 327 | + | fi | |
| 328 | + | ||
| 329 | + | local idx="${t#\!}" # Strip the '!' character | |
| 330 | + | if (( idx < 1 || idx > total )); then bad=1; break; fi | |
| 331 | + | excluded_map[$((idx-1))]=1 | |
| 332 | + | done | |
| 333 | + | ||
| 334 | + | if (( bad )); then | |
| 335 | + | echo " invalid exclusion input; try again." >&2 | |
| 336 | + | continue | |
| 337 | + | fi | |
| 338 | + | ||
| 339 | + | # Build final selection list by adding everything NOT in our exclusion map | |
| 340 | + | for (( i=0; i<total; i++ )); do | |
| 341 | + | if [[ -z "${excluded_map[$i]+abc}" ]]; then | |
| 342 | + | picked+=("${items[i]}") | |
| 343 | + | fi | |
| 344 | + | done | |
| 345 | + | else | |
| 346 | + | # Standard additive parsing (space-separated) | |
| 347 | + | for t in "${toks[@]}"; do | |
| 348 | + | t="${t// /}" | |
| 349 | + | [[ -z "$t" ]] && continue | |
| 350 | + | if [[ ! "$t" =~ ^[0-9]+$ ]]; then bad=1; break; fi | |
| 351 | + | if (( t < 1 || t > total )); then bad=1; break; fi | |
| 352 | + | picked+=("${items[t-1]}") | |
| 353 | + | done | |
| 354 | + | fi | |
| 355 | + | ||
| 310 | 356 | if (( bad )); then | |
| 311 | 357 | echo " invalid input; try again." >&2 | |
| 312 | 358 | continue | |
| @@ -340,7 +386,7 @@ done | |||
| 340 | 386 | echo "Detected ${#CANDIDATES[@]} JetBrains target(s)." | |
| 341 | 387 | mapfile -t SELECTED_IDES < <( | |
| 342 | 388 | printf '%s\n' "${ide_lines[@]}" | | |
| 343 | - | pick_multi "IDEs>" "Pick IDE(s) — TAB to toggle (fzf) or comma indexes" | |
| 389 | + | pick_multi "IDEs>" "Pick IDE(s) — TAB to toggle (fzf) or spaced indexes" | |
| 344 | 390 | ) | |
| 345 | 391 | ||
| 346 | 392 | if (( ${#SELECTED_IDES[@]} == 0 )); then | |
| @@ -362,7 +408,7 @@ done | |||
| 362 | 408 | ||
| 363 | 409 | mapfile -t SELECTED_PLUGIN_LINES < <( | |
| 364 | 410 | printf '%s\n' "${plugin_lines[@]}" | | |
| 365 | - | pick_multi "Plugins>" "Pick plugin(s) — TAB to toggle (fzf) or comma indexes" | |
| 411 | + | pick_multi "Plugins>" "Pick plugin(s) — TAB to toggle (fzf) or spaced indexes" | |
| 366 | 412 | ) | |
| 367 | 413 | ||
| 368 | 414 | if (( ${#SELECTED_PLUGIN_LINES[@]} == 0 )); then | |
| @@ -510,4 +556,4 @@ if (( failed > 0 )); then | |||
| 510 | 556 | echo " - $f" >&2 | |
| 511 | 557 | done | |
| 512 | 558 | exit 1 | |
| 513 | - | fi | |
| 559 | + | fi | |
weehong zrewidował ten Gist 1 month ago. Przejdź do rewizji
1 file changed, 5 insertions, 5 deletions
README.md
| @@ -19,15 +19,15 @@ Replace `<GIST>` with the raw base of this Gist (everything up to and including | |||
| 19 | 19 | ||
| 20 | 20 | ```bash | |
| 21 | 21 | # macOS / Ubuntu (default profile) | |
| 22 | - | curl -sSL <GIST>/install.sh | bash | |
| 22 | + | curl -sSL https://opengist.rmrf.online/weehong/b2a7c0a2ae6d40e8a14f8d85964a9186/raw/HEAD/install.sh | bash | |
| 23 | 23 | ||
| 24 | 24 | # named profile | |
| 25 | - | bash <(curl -sSL <GIST>/install.sh) --profile "WorkSetup" | |
| 25 | + | bash <(curl -sSL https://opengist.rmrf.online/weehong/b2a7c0a2ae6d40e8a14f8d85964a9186/raw/HEAD/install.sh) --profile "WorkSetup" | |
| 26 | 26 | ``` | |
| 27 | 27 | ||
| 28 | 28 | ```powershell | |
| 29 | 29 | # Windows | |
| 30 | - | iwr -useb <GIST>/install.ps1 | iex | |
| 30 | + | iwr -useb https://opengist.rmrf.online/weehong/b2a7c0a2ae6d40e8a14f8d85964a9186/raw/HEAD/install.ps1 | iex | |
| 31 | 31 | ||
| 32 | 32 | # named profile | |
| 33 | 33 | .\install.ps1 -ProfileName "WorkSetup" | |
| @@ -37,12 +37,12 @@ iwr -useb <GIST>/install.ps1 | iex | |||
| 37 | 37 | ||
| 38 | 38 | ```bash | |
| 39 | 39 | # macOS / Ubuntu / WSL2 — interactive picker for IDEs and plugins | |
| 40 | - | bash <(curl -sSL <GIST>/install-jetbrains.sh) | |
| 40 | + | bash <(curl -sSL https://opengist.rmrf.online/weehong/b2a7c0a2ae6d40e8a14f8d85964a9186/raw/HEAD/install-jetbrains.sh) | |
| 41 | 41 | ``` | |
| 42 | 42 | ||
| 43 | 43 | ```powershell | |
| 44 | 44 | # Windows — interactive picker | |
| 45 | - | iwr -useb <GIST>/install-jetbrains.ps1 | iex | |
| 45 | + | iwr -useb https://opengist.rmrf.online/weehong/b2a7c0a2ae6d40e8a14f8d85964a9186/raw/HEAD/install-jetbrains.ps1 | iex | |
| 46 | 46 | ``` | |
| 47 | 47 | ||
| 48 | 48 | --- | |
weehong zrewidował ten Gist 1 month ago. Przejdź do rewizji
3 files changed, 147 insertions, 22 deletions
README.md
| @@ -151,6 +151,8 @@ powershell -ExecutionPolicy Bypass -File .\install.ps1 | |||
| 151 | 151 | ||
| 152 | 152 | **`installPlugins` reports a plugin is already installed.** Harmless — it's a no-op. Both scripts treat it as success. | |
| 153 | 153 | ||
| 154 | + | **"Only one instance of IDEA can be run at a time."** The IDE is currently open and holds the config-dir lock. Both JetBrains installers run a preflight check before installing: if a target IDE looks running, they prompt you to close it and press Enter to retry. If a process slips past the preflight, the install loop short-circuits with the same hint instead of repeating the error per plugin. | |
| 155 | + | ||
| 154 | 156 | **No JetBrains IDEs detected.** Install one via the [JetBrains Toolbox](https://www.jetbrains.com/toolbox-app/) (which sets up the standard paths the script scans), or install standalone — both layouts are supported. | |
| 155 | 157 | ||
| 156 | 158 | **WSL2 picker is empty.** Verify the Windows username is resolved: in WSL run `cmd.exe /c 'echo %USERNAME%'`. If that prints nothing, your `interop.appendWindowsPath` may be disabled; either re-enable it in `/etc/wsl.conf` or run `install-jetbrains.ps1` natively on Windows instead. | |
install-jetbrains.ps1
| @@ -211,6 +211,39 @@ if ($selectedPlugins.Count -eq 0) { | |||
| 211 | 211 | exit 1 | |
| 212 | 212 | } | |
| 213 | 213 | ||
| 214 | + | # ------------------------------------------------------------------ | |
| 215 | + | # Running-IDE preflight | |
| 216 | + | # installPlugins refuses to run while the IDE GUI holds the config-dir lock | |
| 217 | + | # ("Only one instance of IDEA can be run at a time."). Best-effort detection | |
| 218 | + | # via Get-Process. Gateway Client type doesn't need this (no CLI invoked). | |
| 219 | + | # ------------------------------------------------------------------ | |
| 220 | + | function Test-IdeRunning { | |
| 221 | + | param([Parameter(Mandatory)] [psobject]$Ide) | |
| 222 | + | if ($Ide.Type -eq 'Gateway') { return $false } | |
| 223 | + | ||
| 224 | + | # For standalone IDE launchers the process name is the exe basename. | |
| 225 | + | # For Toolbox .cmd shims, the spawned process is e.g. idea64 -> use prefix. | |
| 226 | + | $stem = [System.IO.Path]::GetFileNameWithoutExtension($Ide.Launcher) | |
| 227 | + | $patterns = @($stem) | |
| 228 | + | if ($stem -notmatch '64$') { $patterns += ($stem + '64') } | |
| 229 | + | ||
| 230 | + | foreach ($pat in $patterns) { | |
| 231 | + | if (Get-Process -Name $pat -ErrorAction SilentlyContinue) { return $true } | |
| 232 | + | } | |
| 233 | + | return $false | |
| 234 | + | } | |
| 235 | + | ||
| 236 | + | while ($true) { | |
| 237 | + | $running = @($selectedIdes | Where-Object { Test-IdeRunning $_ }) | |
| 238 | + | if ($running.Count -eq 0) { break } | |
| 239 | + | ||
| 240 | + | Write-Host "" | |
| 241 | + | Write-Host "The following IDE(s) appear to be running — installPlugins needs them closed:" -ForegroundColor Yellow | |
| 242 | + | foreach ($r in $running) { Write-Host (" - {0}" -f $r.Label) -ForegroundColor Yellow } | |
| 243 | + | Write-Host "" | |
| 244 | + | Read-Host "Close them, then press Enter to retry (Ctrl+C to abort)" | Out-Null | |
| 245 | + | } | |
| 246 | + | ||
| 214 | 247 | # ------------------------------------------------------------------ | |
| 215 | 248 | # Install loop | |
| 216 | 249 | # ------------------------------------------------------------------ | |
| @@ -236,10 +269,16 @@ foreach ($ide in $selectedIdes) { | |||
| 236 | 269 | Write-Host (" all {0} plugin(s) ok" -f $selectedPlugins.Count) -ForegroundColor Green | |
| 237 | 270 | $installed += $selectedPlugins.Count | |
| 238 | 271 | } else { | |
| 239 | - | Write-Host (" installPlugins exited {0} FAILED" -f $LASTEXITCODE) -ForegroundColor Red | |
| 272 | + | $joined = ($output | Out-String) | |
| 273 | + | if ($joined -match 'Only one instance') { | |
| 274 | + | Write-Host " IDE is running SKIPPED" -ForegroundColor Yellow | |
| 275 | + | Write-Host " Close the IDE and re-run the script to finish." -ForegroundColor DarkYellow | |
| 276 | + | } else { | |
| 277 | + | Write-Host (" installPlugins exited {0} FAILED" -f $LASTEXITCODE) -ForegroundColor Red | |
| 278 | + | $output | ForEach-Object { Write-Host " $_" -ForegroundColor DarkRed } | |
| 279 | + | } | |
| 240 | 280 | $failed += $selectedPlugins.Count | |
| 241 | 281 | foreach ($p in $selectedPlugins) { $failedList += ("{0} :: {1}" -f $ide.Label, $p.Id) } | |
| 242 | - | $output | ForEach-Object { Write-Host " $_" -ForegroundColor DarkRed } | |
| 243 | 282 | } | |
| 244 | 283 | } catch { | |
| 245 | 284 | Write-Host (" launcher invocation threw FAILED") -ForegroundColor Red | |
| @@ -258,10 +297,16 @@ foreach ($ide in $selectedIdes) { | |||
| 258 | 297 | Write-Host (" all {0} plugin(s) ok" -f $selectedPlugins.Count) -ForegroundColor Green | |
| 259 | 298 | $installed += $selectedPlugins.Count | |
| 260 | 299 | } else { | |
| 261 | - | Write-Host (" installPlugins exited {0} FAILED" -f $LASTEXITCODE) -ForegroundColor Red | |
| 300 | + | $joined = ($output | Out-String) | |
| 301 | + | if ($joined -match 'Only one instance') { | |
| 302 | + | Write-Host " IDE is running SKIPPED" -ForegroundColor Yellow | |
| 303 | + | Write-Host " Close the IDE and re-run the script to finish." -ForegroundColor DarkYellow | |
| 304 | + | } else { | |
| 305 | + | Write-Host (" installPlugins exited {0} FAILED" -f $LASTEXITCODE) -ForegroundColor Red | |
| 306 | + | $output | ForEach-Object { Write-Host " $_" -ForegroundColor DarkRed } | |
| 307 | + | } | |
| 262 | 308 | $failed += $selectedPlugins.Count | |
| 263 | 309 | foreach ($p in $selectedPlugins) { $failedList += ("{0} :: {1}" -f $ide.Label, $p.Id) } | |
| 264 | - | $output | ForEach-Object { Write-Host " $_" -ForegroundColor DarkRed } | |
| 265 | 310 | } | |
| 266 | 311 | } catch { | |
| 267 | 312 | Write-Host (" cmd.exe invocation threw FAILED") -ForegroundColor Red | |
install-jetbrains.sh
| @@ -375,6 +375,66 @@ for line in "${SELECTED_PLUGIN_LINES[@]}"; do | |||
| 375 | 375 | SELECTED_PLUGIN_IDS+=("${label_to_id[$line]}") | |
| 376 | 376 | done | |
| 377 | 377 | ||
| 378 | + | # ------------------------------------------------------------------ | |
| 379 | + | # Running-IDE preflight | |
| 380 | + | # JetBrains' `installPlugins` refuses to run while the IDE GUI is open | |
| 381 | + | # ("Only one instance of IDEA can be run at a time."). We do a best-effort | |
| 382 | + | # pgrep against the IDE app directory so the user can close them upfront | |
| 383 | + | # instead of seeing N identical errors during the install loop. | |
| 384 | + | # ------------------------------------------------------------------ | |
| 385 | + | ide_is_running() { | |
| 386 | + | local launcher="$1" type="$2" | |
| 387 | + | ||
| 388 | + | # remote-dev-server.sh spawns short-lived workers; WSL2->Windows lookups | |
| 389 | + | # would need tasklist.exe — skip in both cases. | |
| 390 | + | case "$type" in | |
| 391 | + | remotedev|wincmd) return 1 ;; | |
| 392 | + | esac | |
| 393 | + | ||
| 394 | + | case "$launcher" in | |
| 395 | + | */Toolbox/apps/*) | |
| 396 | + | # /.../Toolbox/apps/<ide-dir>/[ch-N/<ver>/]bin/idea.sh -> match "<ide-dir>" | |
| 397 | + | local rest="${launcher#*/Toolbox/apps/}" | |
| 398 | + | local ide_dir="${rest%%/*}" | |
| 399 | + | [[ -n "$ide_dir" ]] && pgrep -f -- "/Toolbox/apps/${ide_dir}/" >/dev/null 2>&1 | |
| 400 | + | ;; | |
| 401 | + | */Applications/*.app/*) | |
| 402 | + | local app_path="${launcher%/Contents/MacOS/*}" | |
| 403 | + | pgrep -f -- "${app_path}/Contents/" >/dev/null 2>&1 | |
| 404 | + | ;; | |
| 405 | + | *) | |
| 406 | + | local b | |
| 407 | + | b="$(basename "$launcher")" | |
| 408 | + | b="${b%.sh}" | |
| 409 | + | pgrep -fi -- "$b" >/dev/null 2>&1 | |
| 410 | + | ;; | |
| 411 | + | esac | |
| 412 | + | } | |
| 413 | + | ||
| 414 | + | while :; do | |
| 415 | + | declare -a _running=() | |
| 416 | + | for ide_label in "${SELECTED_IDES[@]}"; do | |
| 417 | + | if ide_is_running "${label_launcher[$ide_label]}" "${label_type[$ide_label]}"; then | |
| 418 | + | _running+=("$ide_label") | |
| 419 | + | fi | |
| 420 | + | done | |
| 421 | + | (( ${#_running[@]} == 0 )) && break | |
| 422 | + | ||
| 423 | + | { | |
| 424 | + | echo | |
| 425 | + | echo "The following IDE(s) appear to be running — installPlugins needs them closed:" | |
| 426 | + | for r in "${_running[@]}"; do | |
| 427 | + | echo " - $r" | |
| 428 | + | done | |
| 429 | + | echo | |
| 430 | + | printf 'Close them, then press Enter to retry (or Ctrl+C to abort): ' | |
| 431 | + | } >&2 | |
| 432 | + | if ! IFS= read -r _ </dev/tty; then | |
| 433 | + | echo "no tty; aborting" >&2 | |
| 434 | + | exit 1 | |
| 435 | + | fi | |
| 436 | + | done | |
| 437 | + | ||
| 378 | 438 | # ------------------------------------------------------------------ | |
| 379 | 439 | # Install loop | |
| 380 | 440 | # ------------------------------------------------------------------ | |
| @@ -389,37 +449,55 @@ echo | |||
| 389 | 449 | echo "Installing ${#SELECTED_PLUGIN_IDS[@]} plugin(s) into ${#SELECTED_IDES[@]} IDE(s)..." | |
| 390 | 450 | echo | |
| 391 | 451 | ||
| 452 | + | handle_single_instance_abort() { | |
| 453 | + | local ide_label="$1" current_pid="$2" | |
| 454 | + | shift 2 | |
| 455 | + | echo | |
| 456 | + | echo " ! '${ide_label}' is still running. Skipping remaining plugins for this IDE." >&2 | |
| 457 | + | echo " ! Close the IDE and re-run the script to finish." >&2 | |
| 458 | + | # Mark current and remaining-for-this-IDE plugins as failed. | |
| 459 | + | local mark_from=0 p | |
| 460 | + | for p in "${SELECTED_PLUGIN_IDS[@]}"; do | |
| 461 | + | if (( mark_from )) || [[ "$p" == "$current_pid" ]]; then | |
| 462 | + | mark_from=1 | |
| 463 | + | failed=$((failed + 1)) | |
| 464 | + | FAILED_LIST+=("${ide_label} :: ${p} (IDE running — close it and re-run)") | |
| 465 | + | fi | |
| 466 | + | done | |
| 467 | + | } | |
| 468 | + | ||
| 392 | 469 | for ide_label in "${SELECTED_IDES[@]}"; do | |
| 393 | 470 | itype="${label_type[$ide_label]}" | |
| 394 | 471 | launcher="${label_launcher[$ide_label]}" | |
| 395 | 472 | ||
| 396 | 473 | echo ">>> $ide_label" | |
| 474 | + | ide_aborted=0 | |
| 397 | 475 | for pid in "${SELECTED_PLUGIN_IDS[@]}"; do | |
| 476 | + | (( ide_aborted )) && break | |
| 398 | 477 | printf ' %-34s ' "$pid" | |
| 478 | + | rc=0 | |
| 399 | 479 | case "$itype" in | |
| 400 | 480 | ide|remotedev) | |
| 401 | - | if "$launcher" installPlugins "$pid" >"$LOG_FILE" 2>&1; then | |
| 402 | - | echo "ok" | |
| 403 | - | installed=$((installed + 1)) | |
| 404 | - | else | |
| 405 | - | echo "FAILED" | |
| 406 | - | failed=$((failed + 1)) | |
| 407 | - | FAILED_LIST+=("${ide_label} :: ${pid}") | |
| 408 | - | sed 's/^/ /' "$LOG_FILE" >&2 || true | |
| 409 | - | fi | |
| 481 | + | "$launcher" installPlugins "$pid" >"$LOG_FILE" 2>&1 || rc=$? | |
| 410 | 482 | ;; | |
| 411 | 483 | wincmd) | |
| 412 | - | if cmd.exe /c "$launcher" installPlugins "$pid" >"$LOG_FILE" 2>&1; then | |
| 413 | - | echo "ok" | |
| 414 | - | installed=$((installed + 1)) | |
| 415 | - | else | |
| 416 | - | echo "FAILED" | |
| 417 | - | failed=$((failed + 1)) | |
| 418 | - | FAILED_LIST+=("${ide_label} :: ${pid}") | |
| 419 | - | sed 's/^/ /' "$LOG_FILE" >&2 || true | |
| 420 | - | fi | |
| 484 | + | cmd.exe /c "$launcher" installPlugins "$pid" >"$LOG_FILE" 2>&1 || rc=$? | |
| 421 | 485 | ;; | |
| 422 | 486 | esac | |
| 487 | + | ||
| 488 | + | if (( rc == 0 )); then | |
| 489 | + | echo "ok" | |
| 490 | + | installed=$((installed + 1)) | |
| 491 | + | elif grep -q "Only one instance" "$LOG_FILE" 2>/dev/null; then | |
| 492 | + | echo "SKIPPED" | |
| 493 | + | handle_single_instance_abort "$ide_label" "$pid" | |
| 494 | + | ide_aborted=1 | |
| 495 | + | else | |
| 496 | + | echo "FAILED" | |
| 497 | + | failed=$((failed + 1)) | |
| 498 | + | FAILED_LIST+=("${ide_label} :: ${pid}") | |
| 499 | + | sed 's/^/ /' "$LOG_FILE" >&2 || true | |
| 500 | + | fi | |
| 423 | 501 | done | |
| 424 | 502 | echo | |
| 425 | 503 | done | |