전체 설치 스크립트 GitHub 릴리스 에셋 검증 및 폴백 다운로드 방어 로직 적용
This commit is contained in:
1 parent
5a67e7bbcf
commit
b41d2f68f3
21 files changed
+507
-156
No files matched your search
@@ -0,0 +1,54 @@
|
||||
# 전체 설치 스크립트 다운로드 안정성 강화 계획 (HARDEN-INSTALL-LINKS-IMP-PLAN)
|
||||
|
||||
## 1. 개요
|
||||
외부 오픈소스 저장소의 릴리스 정책 변경(서브 크레이트 태그 발행, 빌드 진행 중 빈 에셋 상태, 파일명 변경) 및 GitHub API Rate Limit(시간당 60회 제한)으로 인해 설치 스크립트가 실패하는 문제를 방지하기 위해 모든 설치 스크립트(`install-*.sh`, `install-*.ps1`)에 **3단계 방어 로직(Asset-aware Lookup + Fallback Tag + URL Fallback)**을 일괄 적용합니다.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([설치 스크립트 실행]) --> API[GitHub Releases API 조회<br/>User-Agent 헤더 포함]
|
||||
API --> CheckAPI{API 응답 성공?}
|
||||
CheckAPI -- Yes --> AssetSearch["릴리스 목록에서 현재 플랫폼 에셋이<br/>실제로 존재하는(assets > 0) 최신 릴리스 탐색"]
|
||||
AssetSearch --> FoundAsset{에셋 URL 발견?}
|
||||
FoundAsset -- Yes --> DownloadPrimary[1차: 에셋 URL 다운로드 시도]
|
||||
FoundAsset -- No --> FallbackBuild[2차: FALLBACK_TAG 기반 URL 생성]
|
||||
CheckAPI -- No (Rate Limit 등) --> FallbackBuild
|
||||
DownloadPrimary --> CheckDL{다운로드 성공?}
|
||||
CheckDL -- Yes --> ExtractInstall[압축 해제 및 바이너리 설치]
|
||||
CheckDL -- No (404 등) --> FallbackBuild
|
||||
FallbackBuild --> DownloadFallback[FALLBACK_TAG URL로 재시도]
|
||||
DownloadFallback --> ExtractInstall
|
||||
ExtractInstall --> Done([설치 완료])
|
||||
```
|
||||
|
||||
## 2. 작업 단계 및 체크리스트
|
||||
|
||||
### 단계 1: 실행 계획 수립
|
||||
- [x] 작업 계획서(`VIBE-WORK/261031/HARDEN-INSTALL-LINKS-IMP-PLAN.md`) 작성
|
||||
|
||||
### 단계 2: Unix / macOS용 Bash 설치 스크립트(`.sh`) 방어 로직 적용
|
||||
- [x] `install-all-smi.sh`: 에셋 존재 검증, User-Agent 헤더, 다운로드 실패 시 `FALLBACK_VERSION` 자동 재시도 적용
|
||||
- [x] `install-bottom.sh`: `assets` 배열 내 현재 플랫폼 파일(`bottom_${triple}.${ext}`) 존재 여부 확인 및 `FALLBACK_TAG="0.12.3"` / `"nightly"` 폴백 적용
|
||||
- [x] `install-ctop.sh`: `assets` 존재 여부 필터링 및 `FALLBACK_TAG="v0.7.7"` 폴백 다운로드 적용
|
||||
- [x] `install-dua.sh`: 다운로드 실패 시 `FALLBACK_TAG="v2.46.0"` 자동 재시도 보강
|
||||
- [x] `install-helix.sh`: `/releases` 목록에서 `assets`가 존재하는 최신 릴리스 탐색 및 `FALLBACK_TAG="25.07.1"` 폴백 적용
|
||||
- [x] `install-lazydocker.sh`: `assets` 존재 여부 필터링 및 `FALLBACK_TAG="v0.25.2"` 폴백 다운로드 적용
|
||||
- [x] `install-lazygit.sh`: `assets` 존재 여부 필터링, 중복 함수 정리 및 `FALLBACK_TAG="v0.61.1"` 폴백 다운로드 적용
|
||||
- [x] `install-ocr.sh`: 에셋 존재 검증 및 다운로드 실패 시 `FALLBACK_VERSION="v1.3.19"` 자동 재시도 적용
|
||||
- [x] `install-ttyd.sh`: 에셋 존재 검증 및 `FALLBACK_TAG="1.7.7"` 폴백 다운로드 적용
|
||||
|
||||
### 단계 3: Windows용 PowerShell 설치 스크립트(`.ps1`) 방어 로직 적용
|
||||
- [x] `install-all-smi.ps1`: 에셋 검증 및 다운로드 실패 시 `FALLBACK_VERSION` 자동 재시도 적용
|
||||
- [x] `install-bottom.ps1`: 에셋 존재 검증 및 `FALLBACK_TAG` 폴백 다운로드 적용
|
||||
- [x] `install-ctop.ps1`: 에셋 존재 검증 및 `FALLBACK_TAG="v0.7.7"` 폴백 다운로드 적용
|
||||
- [x] `install-dua.ps1`: 다운로드 실패 시 `FALLBACK_TAG="v2.46.0"` 자동 재시도 보강
|
||||
- [x] `install-helix.ps1`: API 실패 또는 에셋 미발견 시 `FALLBACK_TAG="25.07.1"` 폴백 다운로드 적용
|
||||
- [x] `install-lazydocker.ps1`: 에셋 존재 검증 및 `FALLBACK_TAG="v0.25.2"` 폴백 다운로드 적용
|
||||
- [x] `install-lazygit.ps1`: Git for Windows 및 lazygit 에셋 검증, `FALLBACK_TAG="v0.61.1"` 폴백 다운로드 적용
|
||||
- [x] `install-ocr.ps1`: 다운로드 실패 시 `FALLBACK_VERSION="v1.3.19"` 자동 재시도 적용
|
||||
- [x] `install-ttyd.ps1`: API 실패 또는 에셋 미발견 시 `FALLBACK_TAG="1.7.7"` 폴백 다운로드 적용
|
||||
|
||||
### 단계 4: 문법 검증, 완료 보고서 작성 및 Git 푸시
|
||||
- [x] 모든 `.sh` 스크립트 `bash -n` 문법 검사 통과 확인
|
||||
- [x] 완료 보고서(`VIBE-WORK/261031/HARDEN-INSTALL-LINKS-PHASE01.md`) 작성
|
||||
- [x] `uv tool run --from graphifyy graphify update .` 실행
|
||||
- [x] Git commit 및 push
|
||||
@@ -0,0 +1,28 @@
|
||||
# 전체 설치 스크립트 다운로드 안정성 강화 완료 보고서 (HARDEN-INSTALL-LINKS-PHASE01)
|
||||
|
||||
## 1. 개요
|
||||
외부 오픈소스 저장소들의 릴리스 정책 변화(서브 크레이트 릴리스 혼재, CI 빌드 중 빈 에셋 상태, 파일명 변경)나 GitHub API Rate Limit(시간당 60회 제한)이 발생하더라도 모든 설치 스크립트가 중단 없이 정상 설치되도록 **3단계 방어 로직**을 전체 스크립트(`install-*.sh`, `install-*.ps1`)에 일괄 적용하였습니다.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Step1["1단계: 에셋 존재 검증<br/>(assets 배열이 비어있지 않은<br/>릴리스만 선택)"] --> Step2["2단계: API 폴백<br/>(API Rate Limit/오류 시<br/>검증된 FALLBACK_TAG 사용)"]
|
||||
Step2 --> Step3["3단계: 다운로드 폴백<br/>(최신 URL 404/실패 시<br/>FALLBACK_TAG URL로 자동 재시도)"]
|
||||
```
|
||||
|
||||
## 2. 도구별 적용 내역 및 Fallback 버전
|
||||
|
||||
| 도구 | 대상 스크립트 | 에셋 필터링 조건 | 검증된 Fallback 태그 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **all-smi** | `install-all-smi.{sh,ps1}` | `assets.length > 0` | `v0.25.0` |
|
||||
| **bottom** | `install-bottom.{sh,ps1}` | `assets.length > 0` (Nightly & Stable) | `0.12.3` |
|
||||
| **ctop** | `install-ctop.{sh,ps1}` | `prerelease == false && assets.length > 0` | `v0.7.7` |
|
||||
| **dua** | `install-dua.{sh,ps1}` | `prerelease == false && startswith("v") && assets.length > 0` | `v2.46.0` |
|
||||
| **Helix** | `install-helix.{sh,ps1}` | `prerelease == false && assets.length > 0` | `25.07.1` |
|
||||
| **lazydocker** | `install-lazydocker.{sh,ps1}` | `prerelease == false && assets.length > 0` | `v0.25.2` |
|
||||
| **lazygit** | `install-lazygit.{sh,ps1}` | `prerelease == false && assets.length > 0` | `v0.61.1` |
|
||||
| **ocr** | `install-ocr.{sh,ps1}` | `assets.length > 0` | `v1.3.19` |
|
||||
| **ttyd** | `install-ttyd.{sh,ps1}` | `assets.length > 0` | `1.7.7` |
|
||||
|
||||
## 3. 추가 개선 사항
|
||||
- `jq`와 `python3`가 모두 없는 최소 리눅스 컨테이너 환경에서도 `grep`/`sed` 폴백 및 `FALLBACK_TAG`를 통해 설치가 중단되지 않도록 개선했습니다.
|
||||
- 모든 GitHub API 요청에 `User-Agent` 헤더와 타임아웃(`--connect-timeout 10` / `-TimeoutSec 15`)을 명시하여 무한 대기 현상을 방지했습니다.
|
||||
+13
-1
@@ -51,8 +51,10 @@ if ($arch -ne "AMD64" -and $arch -ne "ARM64") {
|
||||
$tag = $null
|
||||
try {
|
||||
Info "Fetching latest release tag from GitHub API..."
|
||||
$response = Invoke-RestMethod -Uri $API_URL -TimeoutSec 10
|
||||
$response = Invoke-RestMethod -Uri $API_URL -Headers @{ 'User-Agent' = 'install-all-smi-ps1' } -TimeoutSec 10
|
||||
if ($response -and $response.assets -and $response.assets.Count -gt 0) {
|
||||
$tag = $response.tag_name
|
||||
}
|
||||
} catch {
|
||||
Warn "Failed to retrieve the latest version from GitHub API. Using fallback version: $FALLBACK_VERSION"
|
||||
$tag = $FALLBACK_VERSION
|
||||
@@ -63,6 +65,7 @@ if (-not $tag) {
|
||||
}
|
||||
|
||||
$downloadUrl = "https://github.com/$REPO/releases/download/$tag/$assetName"
|
||||
$fallbackUrl = "https://github.com/$REPO/releases/download/$FALLBACK_VERSION/$assetName"
|
||||
Info "Resolved download URL: $downloadUrl"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -80,7 +83,16 @@ $destFile = Join-Path $INSTALL_DIR "all-smi.exe"
|
||||
|
||||
try {
|
||||
Info "Downloading binary archive..."
|
||||
try {
|
||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $tempZip -UseBasicParsing
|
||||
} catch {
|
||||
if ($downloadUrl -ne $fallbackUrl) {
|
||||
Warn "Primary download failed. Retrying with fallback version ($FALLBACK_VERSION): $fallbackUrl"
|
||||
Invoke-WebRequest -Uri $fallbackUrl -OutFile $tempZip -UseBasicParsing
|
||||
} else {
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
if (Test-Path $tempExtractDir) {
|
||||
Remove-Item $tempExtractDir -Recurse -Force
|
||||
|
||||
+9
-3
@@ -71,9 +71,9 @@ get_latest_tag() {
|
||||
local json tag
|
||||
info "GitHub API에서 all-smi 최신 릴리즈 정보를 가져오는 중..."
|
||||
|
||||
if json=$(curl -fsSL --connect-timeout 10 "${API_URL}" 2>/dev/null); then
|
||||
if json=$(curl -fsSL -H "User-Agent: install-all-smi-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null); then
|
||||
if command -v jq &>/dev/null; then
|
||||
tag=$(echo "$json" | jq -r '.tag_name')
|
||||
tag=$(echo "$json" | jq -r 'select((.assets | length) > 0) | .tag_name')
|
||||
else
|
||||
# jq가 없는 경우 grep & sed 사용
|
||||
tag=$(echo "$json" | grep '"tag_name":' | head -n 1 | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/')
|
||||
@@ -92,7 +92,7 @@ get_latest_tag() {
|
||||
# 메인 설치 함수
|
||||
# ────────────────────────────────────────────
|
||||
main() {
|
||||
local platform_info asset_name format tag url tmpdir archive_file bin_src
|
||||
local platform_info asset_name format tag url fallback_url tmpdir archive_file bin_src
|
||||
|
||||
platform_info="$(detect_platform)"
|
||||
asset_name="${platform_info%%:*}"
|
||||
@@ -104,6 +104,7 @@ main() {
|
||||
info "적용할 버전 태그: $tag"
|
||||
|
||||
url="https://github.com/${REPO}/releases/download/${tag}/${asset_name}"
|
||||
fallback_url="https://github.com/${REPO}/releases/download/${FALLBACK_VERSION}/${asset_name}"
|
||||
|
||||
# 임시 디렉토리 생성
|
||||
tmpdir="$(mktemp -d)"
|
||||
@@ -113,8 +114,13 @@ main() {
|
||||
|
||||
info "바이너리 아카이브 다운로드 중: $url"
|
||||
if ! curl -fsSL --progress-bar -o "$archive_file" "$url"; then
|
||||
if [[ "$tag" != "$FALLBACK_VERSION" ]]; then
|
||||
warn "최신 버전(${tag}) 다운로드 실패. 검증된 폴백 버전(${FALLBACK_VERSION})으로 재시도합니다: $fallback_url"
|
||||
curl -fsSL --progress-bar -o "$archive_file" "$fallback_url" || error "다운로드 실패: $fallback_url"
|
||||
else
|
||||
error "다운로드 실패: $url"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "압축 해제 중..."
|
||||
case "$format" in
|
||||
|
||||
+28
-15
@@ -1,4 +1,4 @@
|
||||
#Requires -Version 5.1
|
||||
#Requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installs bottom(btm) process monitor from GitHub Nightly releases.
|
||||
@@ -48,6 +48,7 @@ $ErrorActionPreference = 'Stop'
|
||||
# ────────────────────────────────────────────
|
||||
$REPO = "ClementTsang/bottom"
|
||||
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
||||
$FALLBACK_TAG = "0.12.3"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
# Utility functions
|
||||
@@ -98,25 +99,26 @@ function Get-Platform {
|
||||
# Get latest Nightly release tag
|
||||
# ────────────────────────────────────────────
|
||||
function Get-LatestNightlyTag {
|
||||
Write-Info "Fetching latest Nightly release from GitHub API..."
|
||||
Write-Info "Fetching latest release from GitHub API..."
|
||||
|
||||
try {
|
||||
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
||||
-Headers @{ 'User-Agent' = 'install-bottom-ps1' }
|
||||
} catch {
|
||||
Write-Err "Failed to call GitHub API: $_"
|
||||
}
|
||||
-Headers @{ 'User-Agent' = 'install-bottom-ps1' } -TimeoutSec 15
|
||||
|
||||
# Get first item where prerelease=true and tag_name starts with 'nightly-'
|
||||
$nightly = $releases | Where-Object {
|
||||
$_.prerelease -eq $true -and $_.tag_name -like 'nightly-*'
|
||||
$_.assets -and $_.assets.Count -gt 0 -and
|
||||
(($_.prerelease -eq $true -and $_.tag_name -like 'nightly-*') -or $_.prerelease -eq $false)
|
||||
} | Select-Object -First 1
|
||||
|
||||
if (-not $nightly) {
|
||||
Write-Err "Could not find Nightly release."
|
||||
if ($nightly -and $nightly.tag_name) {
|
||||
return $nightly.tag_name
|
||||
}
|
||||
} catch {
|
||||
Write-Warn "GitHub API lookup failed: $_"
|
||||
}
|
||||
|
||||
return $nightly.tag_name
|
||||
Write-Warn "Using fallback release tag: $FALLBACK_TAG"
|
||||
return $FALLBACK_TAG
|
||||
}
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -132,7 +134,7 @@ function Get-DownloadUrl {
|
||||
# Download, extract & install
|
||||
# ────────────────────────────────────────────
|
||||
function Install-Bottom {
|
||||
param([string]$Url)
|
||||
param([string]$Url, [string]$FallbackUrl)
|
||||
|
||||
# Create temp directory
|
||||
$tmpDir = Join-Path $env:TEMP "bottom_install_$(Get-Random)"
|
||||
@@ -143,13 +145,23 @@ function Install-Bottom {
|
||||
|
||||
Write-Info "Downloading: $Url"
|
||||
try {
|
||||
# Suppress progress bar in PowerShell 5+
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
||||
$ProgressPreference = 'Continue'
|
||||
} catch {
|
||||
if ($FallbackUrl -and ($FallbackUrl -ne $Url)) {
|
||||
Write-Warn "Primary download failed. Retrying with fallback URL: $FallbackUrl"
|
||||
try {
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $FallbackUrl -OutFile $zipPath -UseBasicParsing
|
||||
$ProgressPreference = 'Continue'
|
||||
} catch {
|
||||
Write-Err "Download failed: $_"
|
||||
}
|
||||
} else {
|
||||
Write-Err "Download failed: $_"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Info "Extracting..."
|
||||
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
||||
@@ -220,10 +232,11 @@ function Main {
|
||||
Write-Info "Detected platform: $triple"
|
||||
|
||||
$tag = Get-LatestNightlyTag
|
||||
Write-Info "Latest Nightly tag: $tag"
|
||||
Write-Info "Release tag: $tag"
|
||||
|
||||
$url = Get-DownloadUrl -Tag $tag -Triple $triple
|
||||
Install-Bottom -Url $url
|
||||
$fallbackUrl = Get-DownloadUrl -Tag $FALLBACK_TAG -Triple $triple
|
||||
Install-Bottom -Url $url -FallbackUrl $fallbackUrl
|
||||
|
||||
if ($AddToPath) {
|
||||
Add-ToUserPath -Dir $InstallDir
|
||||
|
||||
+33
-15
@@ -18,6 +18,7 @@ set -euo pipefail
|
||||
# ────────────────────────────────────────────
|
||||
REPO="ClementTsang/bottom"
|
||||
API_URL="https://api.github.com/repos/${REPO}/releases"
|
||||
FALLBACK_TAG="0.12.3"
|
||||
INSTALL_DIR="${HOME}/.local/bin"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -35,23 +36,26 @@ for cmd in curl uname; do
|
||||
command -v "$cmd" &>/dev/null || error "'$cmd' 명령어가 필요합니다."
|
||||
done
|
||||
|
||||
# Fallback: use python3 if jq is not available
|
||||
# Fallback: use python3 or grep if jq is not available
|
||||
if command -v jq &>/dev/null; then
|
||||
_json_nightly_tag() {
|
||||
jq -r '[.[] | select(.prerelease==true and (.tag_name | startswith("nightly-")))] | .[0].tag_name'
|
||||
jq -r '[.[] | select((.assets | length) > 0 and ((.prerelease==true and (.tag_name | startswith("nightly-"))) or .prerelease==false))] | .[0].tag_name'
|
||||
}
|
||||
else
|
||||
command -v python3 &>/dev/null || error "'jq' or 'python3' is required."
|
||||
elif command -v python3 &>/dev/null; then
|
||||
_json_nightly_tag() {
|
||||
python3 -c "
|
||||
import sys, json
|
||||
data = json.load(sys.stdin)
|
||||
for r in data:
|
||||
if r.get('prerelease') and r.get('tag_name','').startswith('nightly-'):
|
||||
if r.get('assets') and ((r.get('prerelease') and r.get('tag_name','').startswith('nightly-')) or not r.get('prerelease')):
|
||||
print(r['tag_name'])
|
||||
break
|
||||
"
|
||||
}
|
||||
else
|
||||
_json_nightly_tag() {
|
||||
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||
}
|
||||
fi
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -131,15 +135,19 @@ detect_platform() {
|
||||
# Get latest Nightly release tag
|
||||
# ────────────────────────────────────────────
|
||||
get_latest_nightly_tag() {
|
||||
info "Fetching latest Nightly release from GitHub API..."
|
||||
info "Fetching latest release from GitHub API..."
|
||||
|
||||
local releases
|
||||
releases="$(curl -fsSL "${API_URL}")" || error "Failed to call GitHub API."
|
||||
local releases="" tag=""
|
||||
releases="$(curl -fsSL -H "User-Agent: install-bottom-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null)" || true
|
||||
|
||||
local tag
|
||||
tag="$(echo "$releases" | _json_nightly_tag)"
|
||||
if [[ -n "$releases" ]]; then
|
||||
tag="$(echo "$releases" | _json_nightly_tag 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
[[ -z "$tag" || "$tag" == "null" ]] && error "Could not find Nightly release tag."
|
||||
if [[ -z "$tag" || "$tag" == "null" ]]; then
|
||||
warn "Could not fetch release tag from GitHub API. Using fallback tag: ${FALLBACK_TAG}"
|
||||
tag="${FALLBACK_TAG}"
|
||||
fi
|
||||
echo "$tag"
|
||||
}
|
||||
|
||||
@@ -161,6 +169,7 @@ download_and_install() {
|
||||
local url="$1"
|
||||
local ext="$2" # tar.gz | zip
|
||||
local is_windows="${3:-false}"
|
||||
local fallback_url="${4:-}"
|
||||
|
||||
local tmpdir
|
||||
tmpdir="$(mktemp -d)"
|
||||
@@ -170,8 +179,15 @@ download_and_install() {
|
||||
filename="${url##*/}"
|
||||
|
||||
info "Downloading: $url"
|
||||
curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url" \
|
||||
|| error "Download failed: $url"
|
||||
if ! curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url"; then
|
||||
if [[ -n "$fallback_url" && "$fallback_url" != "$url" ]]; then
|
||||
warn "Primary download failed. Retrying with fallback URL: $fallback_url"
|
||||
curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$fallback_url" \
|
||||
|| error "Download failed: $fallback_url"
|
||||
else
|
||||
error "Download failed: $url"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "Extracting..."
|
||||
case "$ext" in
|
||||
@@ -239,10 +255,12 @@ main() {
|
||||
[[ "$triple" == *"windows"* ]] && is_windows="true"
|
||||
|
||||
tag="$(get_latest_nightly_tag)"
|
||||
info "Latest Nightly tag: $tag"
|
||||
info "Release tag: $tag"
|
||||
|
||||
url="$(build_download_url "$tag" "$triple" "$ext")"
|
||||
download_and_install "$url" "$ext" "$is_windows"
|
||||
local fallback_url
|
||||
fallback_url="$(build_download_url "$FALLBACK_TAG" "$triple" "$ext")"
|
||||
download_and_install "$url" "$ext" "$is_windows" "$fallback_url"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
+28
-12
@@ -1,4 +1,4 @@
|
||||
#Requires -Version 5.1
|
||||
#Requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installs ctop (container terminal UI) from GitHub releases.
|
||||
@@ -49,6 +49,7 @@ $ErrorActionPreference = 'Stop'
|
||||
# ────────────────────────────────────────────
|
||||
$REPO = "bcicen/ctop"
|
||||
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
||||
$FALLBACK_TAG = "v0.7.7"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
# Utility functions
|
||||
@@ -106,18 +107,21 @@ function Get-LatestTag {
|
||||
|
||||
try {
|
||||
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
||||
-Headers @{ 'User-Agent' = 'install-ctop-ps1' }
|
||||
} catch {
|
||||
Write-Err "Failed to call GitHub API: $_"
|
||||
}
|
||||
-Headers @{ 'User-Agent' = 'install-ctop-ps1' } -TimeoutSec 15
|
||||
|
||||
$latest = $releases | Where-Object { $_.prerelease -eq $false } | Select-Object -First 1
|
||||
|
||||
if (-not $latest) {
|
||||
Write-Err "Could not find latest release."
|
||||
}
|
||||
$latest = $releases | Where-Object {
|
||||
$_.prerelease -eq $false -and $_.assets -and $_.assets.Count -gt 0
|
||||
} | Select-Object -First 1
|
||||
|
||||
if ($latest -and $latest.tag_name) {
|
||||
return $latest.tag_name
|
||||
}
|
||||
} catch {
|
||||
Write-Warn "GitHub API lookup failed: $_"
|
||||
}
|
||||
|
||||
Write-Warn "Using fallback release tag: $FALLBACK_TAG"
|
||||
return $FALLBACK_TAG
|
||||
}
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -135,7 +139,7 @@ function Get-DownloadUrl {
|
||||
# Download & install (raw binary — no archive extraction needed)
|
||||
# ────────────────────────────────────────────
|
||||
function Install-Ctop {
|
||||
param([string]$Url)
|
||||
param([string]$Url, [string]$FallbackUrl)
|
||||
|
||||
$tmpDir = Join-Path $env:TEMP "ctop_install_$(Get-Random)"
|
||||
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
||||
@@ -148,9 +152,20 @@ function Install-Ctop {
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $Url -OutFile $binPath -UseBasicParsing
|
||||
$ProgressPreference = 'Continue'
|
||||
} catch {
|
||||
if ($FallbackUrl -and ($FallbackUrl -ne $Url)) {
|
||||
Write-Warn "Primary download failed. Retrying with fallback URL: $FallbackUrl"
|
||||
try {
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $FallbackUrl -OutFile $binPath -UseBasicParsing
|
||||
$ProgressPreference = 'Continue'
|
||||
} catch {
|
||||
Write-Err "Download failed: $_"
|
||||
}
|
||||
} else {
|
||||
Write-Err "Download failed: $_"
|
||||
}
|
||||
}
|
||||
|
||||
# Create install directory
|
||||
if (-not (Test-Path $InstallDir)) {
|
||||
@@ -210,7 +225,8 @@ function Main {
|
||||
Write-Info "Latest release: $tag"
|
||||
|
||||
$url = Get-DownloadUrl -Tag $tag -Platform $platform
|
||||
Install-Ctop -Url $url
|
||||
$fallbackUrl = Get-DownloadUrl -Tag $FALLBACK_TAG -Platform $platform
|
||||
Install-Ctop -Url $url -FallbackUrl $fallbackUrl
|
||||
|
||||
if ($AddToPath) {
|
||||
Add-ToUserPath -Dir $InstallDir
|
||||
|
||||
+31
-13
@@ -16,6 +16,7 @@ set -euo pipefail
|
||||
# ────────────────────────────────────────────
|
||||
REPO="bcicen/ctop"
|
||||
API_URL="https://api.github.com/repos/${REPO}/releases"
|
||||
FALLBACK_TAG="v0.7.7"
|
||||
INSTALL_DIR="${HOME}/.local/bin"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -33,23 +34,26 @@ for cmd in curl uname; do
|
||||
command -v "$cmd" &>/dev/null || error "'$cmd' command is required."
|
||||
done
|
||||
|
||||
# Fallback: use python3 if jq is not available
|
||||
# Fallback: use python3 or grep if jq is not available
|
||||
if command -v jq &>/dev/null; then
|
||||
_json_latest_tag() {
|
||||
jq -r '[.[] | select(.prerelease==false)] | .[0].tag_name'
|
||||
jq -r '[.[] | select(.prerelease==false and ((.assets | length) > 0))] | .[0].tag_name'
|
||||
}
|
||||
else
|
||||
command -v python3 &>/dev/null || error "'jq' or 'python3' is required."
|
||||
elif command -v python3 &>/dev/null; then
|
||||
_json_latest_tag() {
|
||||
python3 -c "
|
||||
import sys, json
|
||||
data = json.load(sys.stdin)
|
||||
for r in data:
|
||||
if not r.get('prerelease'):
|
||||
if not r.get('prerelease') and r.get('assets'):
|
||||
print(r['tag_name'])
|
||||
break
|
||||
"
|
||||
}
|
||||
else
|
||||
_json_latest_tag() {
|
||||
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||
}
|
||||
fi
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -118,13 +122,17 @@ detect_platform() {
|
||||
get_latest_tag() {
|
||||
info "Fetching latest release from GitHub API..."
|
||||
|
||||
local releases
|
||||
releases="$(curl -fsSL "${API_URL}")" || error "Failed to call GitHub API."
|
||||
local releases="" tag=""
|
||||
releases="$(curl -fsSL -H "User-Agent: install-ctop-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null)" || true
|
||||
|
||||
local tag
|
||||
tag="$(echo "$releases" | _json_latest_tag)"
|
||||
if [[ -n "$releases" ]]; then
|
||||
tag="$(echo "$releases" | _json_latest_tag 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
[[ -z "$tag" || "$tag" == "null" ]] && error "Could not find latest release tag."
|
||||
if [[ -z "$tag" || "$tag" == "null" ]]; then
|
||||
warn "Could not fetch latest release tag from GitHub API. Using fallback tag: ${FALLBACK_TAG}"
|
||||
tag="${FALLBACK_TAG}"
|
||||
fi
|
||||
echo "$tag"
|
||||
}
|
||||
|
||||
@@ -146,6 +154,7 @@ build_download_url() {
|
||||
# ────────────────────────────────────────────
|
||||
download_and_install() {
|
||||
local url="$1"
|
||||
local fallback_url="${2:-}"
|
||||
|
||||
local tmpdir
|
||||
tmpdir="$(mktemp -d)"
|
||||
@@ -155,8 +164,15 @@ download_and_install() {
|
||||
filename="${url##*/}"
|
||||
|
||||
info "Downloading: $url"
|
||||
curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url" \
|
||||
|| error "Download failed: $url"
|
||||
if ! curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url"; then
|
||||
if [[ -n "$fallback_url" && "$fallback_url" != "$url" ]]; then
|
||||
warn "Primary download failed. Retrying with fallback URL: $fallback_url"
|
||||
curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$fallback_url" \
|
||||
|| error "Download failed: $fallback_url"
|
||||
else
|
||||
error "Download failed: $url"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ctop provides raw binaries (not archives), so skip extraction
|
||||
local bin_src="${tmpdir}/${filename}"
|
||||
@@ -194,7 +210,9 @@ main() {
|
||||
info "Latest release: $tag"
|
||||
|
||||
url="$(build_download_url "$tag" "$platform")"
|
||||
download_and_install "$url"
|
||||
local fallback_url
|
||||
fallback_url="$(build_download_url "$FALLBACK_TAG" "$platform")"
|
||||
download_and_install "$url" "$fallback_url"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
+14
-2
@@ -127,7 +127,7 @@ function Get-DownloadUrl {
|
||||
# Download, extract & install
|
||||
# ────────────────────────────────────────────
|
||||
function Install-Dua {
|
||||
param([string]$Url)
|
||||
param([string]$Url, [string]$FallbackUrl)
|
||||
|
||||
$tmpDir = Join-Path $env:TEMP "dua_install_$(Get-Random)"
|
||||
New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null
|
||||
@@ -141,8 +141,19 @@ function Install-Dua {
|
||||
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
||||
$ProgressPreference = 'Continue'
|
||||
} catch {
|
||||
if ($FallbackUrl -and ($FallbackUrl -ne $Url)) {
|
||||
Warn "Primary download failed. Retrying with fallback URL: $FallbackUrl"
|
||||
try {
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $FallbackUrl -OutFile $zipPath -UseBasicParsing
|
||||
$ProgressPreference = 'Continue'
|
||||
} catch {
|
||||
ErrExit "Download failed from $FallbackUrl : $_"
|
||||
}
|
||||
} else {
|
||||
ErrExit "Download failed from $Url : $_"
|
||||
}
|
||||
}
|
||||
|
||||
Info "Extracting archive..."
|
||||
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
||||
@@ -218,7 +229,8 @@ function Main {
|
||||
Info "Release tag: $tag"
|
||||
|
||||
$url = Get-DownloadUrl -Tag $tag -Triple $triple
|
||||
$duaBin = Install-Dua -Url $url
|
||||
$fallbackUrl = Get-DownloadUrl -Tag $FALLBACK_TAG -Triple $triple
|
||||
$duaBin = Install-Dua -Url $url -FallbackUrl $fallbackUrl
|
||||
|
||||
if ($AddToPath) {
|
||||
Add-ToUserPath -Dir $InstallDir
|
||||
|
||||
+10
-1
@@ -145,13 +145,22 @@ install_from_github() {
|
||||
tag="$(get_latest_tag)"
|
||||
local filename="dua-${tag}-${target}.tar.gz"
|
||||
local download_url="https://github.com/${REPO}/releases/download/${tag}/${filename}"
|
||||
local fallback_filename="dua-${FALLBACK_TAG}-${target}.tar.gz"
|
||||
local fallback_url="https://github.com/${REPO}/releases/download/${FALLBACK_TAG}/${fallback_filename}"
|
||||
|
||||
info "Downloading: $download_url"
|
||||
TMPDIR="$(mktemp -d)"
|
||||
trap '[[ -d "${TMPDIR:-}" ]] && rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
curl -fsSL --progress-bar -o "${TMPDIR}/${filename}" "$download_url" ||
|
||||
if ! curl -fsSL --progress-bar -o "${TMPDIR}/${filename}" "$download_url"; then
|
||||
if [[ "$tag" != "$FALLBACK_TAG" ]]; then
|
||||
warn "Primary download failed. Retrying with fallback tag (${FALLBACK_TAG}): $fallback_url"
|
||||
curl -fsSL --progress-bar -o "${TMPDIR}/${filename}" "$fallback_url" ||
|
||||
error "Download failed: $fallback_url"
|
||||
else
|
||||
error "Download failed: $download_url"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "Extracting..."
|
||||
tar -xzf "${TMPDIR}/${filename}" -C "$TMPDIR"
|
||||
|
||||
+28
-8
@@ -58,7 +58,8 @@ function Write-Err { param([string]$msg) Write-Host "[ERROR] $msg" -Foregrou
|
||||
# 상수 정의
|
||||
# ────────────────────────────────────────────
|
||||
$REPO = "helix-editor/helix"
|
||||
$API_URL = "https://api.github.com/repos/$REPO/releases/latest"
|
||||
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
||||
$FALLBACK_TAG = "25.07.1"
|
||||
$HELIX_CONFIG_DIR = Join-Path $env:APPDATA "helix"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -76,27 +77,37 @@ function Main {
|
||||
|
||||
# 2) GitHub 최신 릴리스 정보 획득
|
||||
Write-Info "Fetching latest Helix release information from GitHub API..."
|
||||
$release = $null
|
||||
$tagName = $FALLBACK_TAG
|
||||
try {
|
||||
$release = Invoke-RestMethod -Uri $API_URL -UseBasicParsing -Headers @{ 'User-Agent' = 'install-helix-ps1' }
|
||||
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing -Headers @{ 'User-Agent' = 'install-helix-ps1' } -TimeoutSec 15
|
||||
$release = $releases | Where-Object { $_.prerelease -eq $false -and $_.assets -and $_.assets.Count -gt 0 } | Select-Object -First 1
|
||||
if ($release -and $release.tag_name) {
|
||||
$tagName = $release.tag_name
|
||||
}
|
||||
} catch {
|
||||
Write-Err "GitHub API call failed: $_"
|
||||
Write-Warn "GitHub API call failed: $_. Using fallback tag: $FALLBACK_TAG"
|
||||
}
|
||||
|
||||
$tagName = $release.tag_name
|
||||
$version = $tagName -replace '^v', ''
|
||||
Write-Info "Latest Helix version confirmed: $tagName"
|
||||
Write-Info "Target Helix version: $tagName"
|
||||
|
||||
# 3) 윈도우 x86_64용 zip 파일 에셋 탐색
|
||||
$asset = $null
|
||||
if ($release -and $release.assets) {
|
||||
$asset = $release.assets | Where-Object { $_.name -like "*-x86_64-windows.zip" } | Select-Object -First 1
|
||||
}
|
||||
if (-not $asset) {
|
||||
# 에셋 조회가 되지 않을 경우 릴리스 패턴에 맞추어 다운로드 URL 직접 빌드
|
||||
$zipName = "helix-${version}-x86_64-windows.zip"
|
||||
$downloadUrl = "https://github.com/$REPO/releases/download/$tagName/$zipName"
|
||||
Write-Warn "Could not find asset in GitHub response. Trying fallback URL: $downloadUrl"
|
||||
Write-Info "Resolved URL: $downloadUrl"
|
||||
} else {
|
||||
$zipName = $asset.name
|
||||
$downloadUrl = $asset.browser_download_url
|
||||
}
|
||||
$fallbackVersion = $FALLBACK_TAG -replace '^v', ''
|
||||
$fallbackZipName = "helix-${fallbackVersion}-x86_64-windows.zip"
|
||||
$fallbackUrl = "https://github.com/$REPO/releases/download/$FALLBACK_TAG/$fallbackZipName"
|
||||
|
||||
# 4) 임시 작업 디렉토리 생성 및 아카이브 다운로드
|
||||
$tmpDir = Join-Path $env:TEMP "helix_install_$(Get-Random)"
|
||||
@@ -105,8 +116,17 @@ function Main {
|
||||
|
||||
try {
|
||||
Write-Info "Downloading archive: $downloadUrl"
|
||||
$ProgressPreference = 'SilentlyContinue' # 다운로드 속도 향상을 위해 진행바 숨김
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
try {
|
||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $tmpZipPath -UseBasicParsing
|
||||
} catch {
|
||||
if ($downloadUrl -ne $fallbackUrl) {
|
||||
Write-Warn "Primary download failed. Retrying with fallback version ($FALLBACK_TAG): $fallbackUrl"
|
||||
Invoke-WebRequest -Uri $fallbackUrl -OutFile $tmpZipPath -UseBasicParsing
|
||||
} else {
|
||||
throw
|
||||
}
|
||||
}
|
||||
$ProgressPreference = 'Continue'
|
||||
|
||||
# 5) 압축 해제
|
||||
|
||||
+33
-10
@@ -14,7 +14,8 @@ set -euo pipefail
|
||||
# 상수 정의
|
||||
# ────────────────────────────────────────────
|
||||
REPO="helix-editor/helix"
|
||||
API_URL="https://api.github.com/repos/${REPO}/releases/latest"
|
||||
API_URL="https://api.github.com/repos/${REPO}/releases"
|
||||
FALLBACK_TAG="25.07.1"
|
||||
INSTALL_DIR="${HOME}/.local/bin"
|
||||
HELIX_CONFIG_DIR="${HOME}/.config/helix"
|
||||
|
||||
@@ -33,20 +34,26 @@ for cmd in curl tar xz uname; do
|
||||
command -v "$cmd" &>/dev/null || error "'$cmd' 명령어가 필요합니다. 먼저 설치해 주세요."
|
||||
done
|
||||
|
||||
# Fallback: jq가 없을 경우 python3를 사용해 JSON 분석
|
||||
# Fallback: jq가 없을 경우 python3 또는 grep을 사용해 JSON 분석
|
||||
if command -v jq &>/dev/null; then
|
||||
_json_latest_tag() {
|
||||
jq -r '.tag_name'
|
||||
jq -r '[.[] | select(.prerelease==false and ((.assets | length) > 0))] | .[0].tag_name'
|
||||
}
|
||||
else
|
||||
command -v python3 &>/dev/null || error "'jq' 또는 'python3' 명령어가 설치되어 있어야 합니다."
|
||||
elif command -v python3 &>/dev/null; then
|
||||
_json_latest_tag() {
|
||||
python3 -c "
|
||||
import sys, json
|
||||
data = json.load(sys.stdin)
|
||||
print(data.get('tag_name', ''))
|
||||
for r in data:
|
||||
if not r.get('prerelease') and r.get('assets'):
|
||||
print(r.get('tag_name', ''))
|
||||
break
|
||||
"
|
||||
}
|
||||
else
|
||||
_json_latest_tag() {
|
||||
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||
}
|
||||
fi
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -93,12 +100,15 @@ detect_platform() {
|
||||
get_latest_release_tag() {
|
||||
info "GitHub API를 통해 Helix 최신 릴리스 버전을 조회하는 중..."
|
||||
|
||||
local release_json tag
|
||||
release_json="$(curl -fsSL "${API_URL}")" || error "GitHub API 호출에 실패했습니다."
|
||||
local release_json="" tag=""
|
||||
release_json="$(curl -fsSL -H "User-Agent: install-helix-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null)" || true
|
||||
|
||||
tag="$(echo "$release_json" | _json_latest_tag)"
|
||||
if [[ -n "$release_json" ]]; then
|
||||
tag="$(echo "$release_json" | _json_latest_tag 2>/dev/null || true)"
|
||||
fi
|
||||
if [[ -z "$tag" || "$tag" == "null" ]]; then
|
||||
error "최신 릴리스 태그를 확인하는 데 실패했습니다."
|
||||
warn "최신 릴리스 태그 조회 실패. 검증된 폴백 버전(${FALLBACK_TAG})을 사용합니다."
|
||||
tag="${FALLBACK_TAG}"
|
||||
fi
|
||||
echo "$tag"
|
||||
}
|
||||
@@ -126,10 +136,23 @@ main() {
|
||||
local tmp_archive="${tmp_dir}/${archive_name}"
|
||||
|
||||
info "아카이브 다운로드 중: $download_url"
|
||||
if ! curl -fsSL "$download_url" -o "$tmp_archive"; then
|
||||
if [[ "$tag" != "$FALLBACK_TAG" ]]; then
|
||||
tag="${FALLBACK_TAG}"
|
||||
version="${tag#v}"
|
||||
asset_name="helix-${version}-${platform_arch}"
|
||||
archive_name="${asset_name}.tar.xz"
|
||||
download_url="https://github.com/helix-editor/helix/releases/download/${tag}/${archive_name}"
|
||||
warn "다운로드 실패. 폴백 버전(${FALLBACK_TAG})으로 재시도합니다: $download_url"
|
||||
if ! curl -fsSL "$download_url" -o "$tmp_archive"; then
|
||||
rm -rf "$tmp_dir"
|
||||
error "바이너리 다운로드에 실패했습니다. URL: $download_url"
|
||||
fi
|
||||
else
|
||||
rm -rf "$tmp_dir"
|
||||
error "바이너리 다운로드에 실패했습니다. URL: $download_url"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "압축 해제 중..."
|
||||
tar -xf "$tmp_archive" -C "$tmp_dir"
|
||||
|
||||
+27
-11
@@ -48,6 +48,7 @@ $ErrorActionPreference = 'Stop'
|
||||
# ────────────────────────────────────────────
|
||||
$REPO = "jesseduffield/lazydocker"
|
||||
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
||||
$FALLBACK_TAG = "v0.25.2"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
# Utility functions
|
||||
@@ -96,18 +97,21 @@ function Get-LatestTag {
|
||||
|
||||
try {
|
||||
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
||||
-Headers @{ 'User-Agent' = 'install-lazydocker-ps1' }
|
||||
} catch {
|
||||
Write-Err "Failed to call GitHub API: $_"
|
||||
}
|
||||
-Headers @{ 'User-Agent' = 'install-lazydocker-ps1' } -TimeoutSec 15
|
||||
|
||||
$latest = $releases | Where-Object { $_.prerelease -eq $false } | Select-Object -First 1
|
||||
|
||||
if (-not $latest) {
|
||||
Write-Err "Could not find latest release."
|
||||
}
|
||||
$latest = $releases | Where-Object {
|
||||
$_.prerelease -eq $false -and $_.assets -and $_.assets.Count -gt 0
|
||||
} | Select-Object -First 1
|
||||
|
||||
if ($latest -and $latest.tag_name) {
|
||||
return $latest.tag_name
|
||||
}
|
||||
} catch {
|
||||
Write-Warn "GitHub API lookup failed: $_"
|
||||
}
|
||||
|
||||
Write-Warn "Using fallback release tag: $FALLBACK_TAG"
|
||||
return $FALLBACK_TAG
|
||||
}
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -124,7 +128,7 @@ function Get-DownloadUrl {
|
||||
# Download, extract & install
|
||||
# ────────────────────────────────────────────
|
||||
function Install-Lazydocker {
|
||||
param([string]$Url)
|
||||
param([string]$Url, [string]$FallbackUrl)
|
||||
|
||||
$tmpDir = Join-Path $env:TEMP "lazydocker_install_$(Get-Random)"
|
||||
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
||||
@@ -137,9 +141,20 @@ function Install-Lazydocker {
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
||||
$ProgressPreference = 'Continue'
|
||||
} catch {
|
||||
if ($FallbackUrl -and ($FallbackUrl -ne $Url)) {
|
||||
Write-Warn "Primary download failed. Retrying with fallback URL: $FallbackUrl"
|
||||
try {
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $FallbackUrl -OutFile $zipPath -UseBasicParsing
|
||||
$ProgressPreference = 'Continue'
|
||||
} catch {
|
||||
Write-Err "Download failed: $_"
|
||||
}
|
||||
} else {
|
||||
Write-Err "Download failed: $_"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Info "Extracting..."
|
||||
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
||||
@@ -223,7 +238,8 @@ function Main {
|
||||
Write-Info "Latest release: $tag"
|
||||
|
||||
$url = Get-DownloadUrl -Tag $tag -Platform $platform
|
||||
Install-Lazydocker -Url $url
|
||||
$fallbackUrl = Get-DownloadUrl -Tag $FALLBACK_TAG -Platform $platform
|
||||
Install-Lazydocker -Url $url -FallbackUrl $fallbackUrl
|
||||
|
||||
if ($AddToPath) {
|
||||
Add-ToUserPath -Dir $InstallDir
|
||||
|
||||
+30
-12
@@ -16,6 +16,7 @@ set -euo pipefail
|
||||
# ────────────────────────────────────────────
|
||||
REPO="jesseduffield/lazydocker"
|
||||
API_URL="https://api.github.com/repos/${REPO}/releases"
|
||||
FALLBACK_TAG="v0.25.2"
|
||||
INSTALL_DIR="${HOME}/.local/bin"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -55,23 +56,26 @@ for cmd in curl uname; do
|
||||
command -v "$cmd" &>/dev/null || error "'$cmd' command is required."
|
||||
done
|
||||
|
||||
# Fallback: use python3 if jq is not available
|
||||
# Fallback: use python3 or grep if jq is not available
|
||||
if command -v jq &>/dev/null; then
|
||||
_json_latest_tag() {
|
||||
jq -r '[.[] | select(.prerelease==false)] | .[0].tag_name'
|
||||
jq -r '[.[] | select(.prerelease==false and ((.assets | length) > 0))] | .[0].tag_name'
|
||||
}
|
||||
else
|
||||
command -v python3 &>/dev/null || error "'jq' or 'python3' is required."
|
||||
elif command -v python3 &>/dev/null; then
|
||||
_json_latest_tag() {
|
||||
python3 -c "
|
||||
import sys, json
|
||||
data = json.load(sys.stdin)
|
||||
for r in data:
|
||||
if not r.get('prerelease'):
|
||||
if not r.get('prerelease') and r.get('assets'):
|
||||
print(r['tag_name'])
|
||||
break
|
||||
"
|
||||
}
|
||||
else
|
||||
_json_latest_tag() {
|
||||
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||
}
|
||||
fi
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -124,13 +128,17 @@ detect_platform() {
|
||||
get_latest_tag() {
|
||||
info "Fetching latest release from GitHub API..."
|
||||
|
||||
local releases
|
||||
releases="$(curl -fsSL "${API_URL}")" || error "Failed to call GitHub API."
|
||||
local releases="" tag=""
|
||||
releases="$(curl -fsSL -H "User-Agent: install-lazydocker-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null)" || true
|
||||
|
||||
local tag
|
||||
tag="$(echo "$releases" | _json_latest_tag)"
|
||||
if [[ -n "$releases" ]]; then
|
||||
tag="$(echo "$releases" | _json_latest_tag 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
[[ -z "$tag" || "$tag" == "null" ]] && error "Could not find latest release tag."
|
||||
if [[ -z "$tag" || "$tag" == "null" ]]; then
|
||||
warn "Could not fetch latest release tag from GitHub API. Using fallback tag: ${FALLBACK_TAG}"
|
||||
tag="${FALLBACK_TAG}"
|
||||
fi
|
||||
echo "$tag"
|
||||
}
|
||||
|
||||
@@ -153,6 +161,7 @@ build_download_url() {
|
||||
download_and_install() {
|
||||
local url="$1"
|
||||
local ext="$2"
|
||||
local fallback_url="${3:-}"
|
||||
|
||||
local tmpdir
|
||||
tmpdir="$(mktemp -d)"
|
||||
@@ -162,8 +171,15 @@ download_and_install() {
|
||||
filename="${url##*/}"
|
||||
|
||||
info "Downloading: $url"
|
||||
curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url" ||
|
||||
if ! curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url"; then
|
||||
if [[ -n "$fallback_url" && "$fallback_url" != "$url" ]]; then
|
||||
warn "Primary download failed. Retrying with fallback URL: $fallback_url"
|
||||
curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$fallback_url" ||
|
||||
error "Download failed: $fallback_url"
|
||||
else
|
||||
error "Download failed: $url"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "Extracting..."
|
||||
case "$ext" in
|
||||
@@ -248,7 +264,9 @@ main() {
|
||||
info "Latest release: $tag"
|
||||
|
||||
url="$(build_download_url "$tag" "$platform" "$ext")"
|
||||
download_and_install "$url" "$ext"
|
||||
local fallback_url
|
||||
fallback_url="$(build_download_url "$FALLBACK_TAG" "$platform" "$ext")"
|
||||
download_and_install "$url" "$ext" "$fallback_url"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
+27
-11
@@ -48,6 +48,7 @@ $ErrorActionPreference = 'Stop'
|
||||
# ────────────────────────────────────────────
|
||||
$REPO = "jesseduffield/lazygit"
|
||||
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
||||
$FALLBACK_TAG = "v0.61.1"
|
||||
$GIT_REPO = "git-for-windows/git"
|
||||
$GIT_API_URL = "https://api.github.com/repos/$GIT_REPO/releases"
|
||||
|
||||
@@ -254,18 +255,21 @@ function Get-LatestTag {
|
||||
|
||||
try {
|
||||
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
||||
-Headers @{ 'User-Agent' = 'install-lazygit-ps1' }
|
||||
} catch {
|
||||
Write-Err "Failed to call GitHub API: $_"
|
||||
}
|
||||
-Headers @{ 'User-Agent' = 'install-lazygit-ps1' } -TimeoutSec 15
|
||||
|
||||
$latest = $releases | Where-Object { $_.prerelease -eq $false } | Select-Object -First 1
|
||||
|
||||
if (-not $latest) {
|
||||
Write-Err "Could not find latest release."
|
||||
}
|
||||
$latest = $releases | Where-Object {
|
||||
$_.prerelease -eq $false -and $_.assets -and $_.assets.Count -gt 0
|
||||
} | Select-Object -First 1
|
||||
|
||||
if ($latest -and $latest.tag_name) {
|
||||
return $latest.tag_name
|
||||
}
|
||||
} catch {
|
||||
Write-Warn "GitHub API lookup failed: $_"
|
||||
}
|
||||
|
||||
Write-Warn "Using fallback release tag: $FALLBACK_TAG"
|
||||
return $FALLBACK_TAG
|
||||
}
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -282,7 +286,7 @@ function Get-DownloadUrl {
|
||||
# Download, extract & install
|
||||
# ────────────────────────────────────────────
|
||||
function Install-Lazygit {
|
||||
param([string]$Url)
|
||||
param([string]$Url, [string]$FallbackUrl)
|
||||
|
||||
$tmpDir = Join-Path $env:TEMP "lazygit_install_$(Get-Random)"
|
||||
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
||||
@@ -295,9 +299,20 @@ function Install-Lazygit {
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
||||
$ProgressPreference = 'Continue'
|
||||
} catch {
|
||||
if ($FallbackUrl -and ($FallbackUrl -ne $Url)) {
|
||||
Write-Warn "Primary download failed. Retrying with fallback URL: $FallbackUrl"
|
||||
try {
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $FallbackUrl -OutFile $zipPath -UseBasicParsing
|
||||
$ProgressPreference = 'Continue'
|
||||
} catch {
|
||||
Write-Err "Download failed: $_"
|
||||
}
|
||||
} else {
|
||||
Write-Err "Download failed: $_"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Info "Extracting..."
|
||||
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
||||
@@ -370,7 +385,8 @@ function Main {
|
||||
Write-Info "Latest release: $tag"
|
||||
|
||||
$url = Get-DownloadUrl -Tag $tag -Platform $platform
|
||||
Install-Lazygit -Url $url
|
||||
$fallbackUrl = Get-DownloadUrl -Tag $FALLBACK_TAG -Platform $platform
|
||||
Install-Lazygit -Url $url -FallbackUrl $fallbackUrl
|
||||
|
||||
if ($AddToPath) {
|
||||
Add-ToUserPath -Dir $InstallDir
|
||||
|
||||
+30
-17
@@ -17,6 +17,7 @@ set -euo pipefail
|
||||
# ────────────────────────────────────────────
|
||||
REPO="jesseduffield/lazygit"
|
||||
API_URL="https://api.github.com/repos/${REPO}/releases"
|
||||
FALLBACK_TAG="v0.61.1"
|
||||
INSTALL_DIR="${HOME}/.local/bin"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -48,11 +49,6 @@ ensure_brew() {
|
||||
command -v brew &>/dev/null || error "Homebrew installation failed. Install it manually: https://brew.sh/"
|
||||
success "Homebrew installed"
|
||||
}
|
||||
error() {
|
||||
echo "[ERROR] $*" >&2
|
||||
exit 1
|
||||
}
|
||||
success() { echo "[OK] $*" >&2; }
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
# Check for git (required by lazygit)
|
||||
@@ -105,23 +101,26 @@ for cmd in curl uname; do
|
||||
command -v "$cmd" &>/dev/null || error "'$cmd' command is required."
|
||||
done
|
||||
|
||||
# Fallback: use python3 if jq is not available
|
||||
# Fallback: use python3 or grep if jq is not available
|
||||
if command -v jq &>/dev/null; then
|
||||
_json_latest_tag() {
|
||||
jq -r '[.[] | select(.prerelease==false)] | .[0].tag_name'
|
||||
jq -r '[.[] | select(.prerelease==false and ((.assets | length) > 0))] | .[0].tag_name'
|
||||
}
|
||||
else
|
||||
command -v python3 &>/dev/null || error "'jq' or 'python3' is required."
|
||||
elif command -v python3 &>/dev/null; then
|
||||
_json_latest_tag() {
|
||||
python3 -c "
|
||||
import sys, json
|
||||
data = json.load(sys.stdin)
|
||||
for r in data:
|
||||
if not r.get('prerelease'):
|
||||
if not r.get('prerelease') and r.get('assets'):
|
||||
print(r['tag_name'])
|
||||
break
|
||||
"
|
||||
}
|
||||
else
|
||||
_json_latest_tag() {
|
||||
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||
}
|
||||
fi
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -205,13 +204,17 @@ detect_platform() {
|
||||
get_latest_tag() {
|
||||
info "Fetching latest release from GitHub API..."
|
||||
|
||||
local releases
|
||||
releases="$(curl -fsSL "${API_URL}")" || error "Failed to call GitHub API."
|
||||
local releases="" tag=""
|
||||
releases="$(curl -fsSL -H "User-Agent: install-lazygit-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null)" || true
|
||||
|
||||
local tag
|
||||
tag="$(echo "$releases" | _json_latest_tag)"
|
||||
if [[ -n "$releases" ]]; then
|
||||
tag="$(echo "$releases" | _json_latest_tag 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
[[ -z "$tag" || "$tag" == "null" ]] && error "Could not find latest release tag."
|
||||
if [[ -z "$tag" || "$tag" == "null" ]]; then
|
||||
warn "Could not fetch latest release tag from GitHub API. Using fallback tag: ${FALLBACK_TAG}"
|
||||
tag="${FALLBACK_TAG}"
|
||||
fi
|
||||
echo "$tag"
|
||||
}
|
||||
|
||||
@@ -234,6 +237,7 @@ download_and_install() {
|
||||
local url="$1"
|
||||
local ext="$2"
|
||||
local is_windows="${3:-false}"
|
||||
local fallback_url="${4:-}"
|
||||
|
||||
local tmpdir
|
||||
tmpdir="$(mktemp -d)"
|
||||
@@ -243,8 +247,15 @@ download_and_install() {
|
||||
filename="${url##*/}"
|
||||
|
||||
info "Downloading: $url"
|
||||
curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url" ||
|
||||
if ! curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url"; then
|
||||
if [[ -n "$fallback_url" && "$fallback_url" != "$url" ]]; then
|
||||
warn "Primary download failed. Retrying with fallback URL: $fallback_url"
|
||||
curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$fallback_url" ||
|
||||
error "Download failed: $fallback_url"
|
||||
else
|
||||
error "Download failed: $url"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "Extracting..."
|
||||
case "$ext" in
|
||||
@@ -313,7 +324,9 @@ main() {
|
||||
info "Latest release: $tag"
|
||||
|
||||
url="$(build_download_url "$tag" "$platform" "$ext")"
|
||||
download_and_install "$url" "$ext" "$is_windows"
|
||||
local fallback_url
|
||||
fallback_url="$(build_download_url "$FALLBACK_TAG" "$platform" "$ext")"
|
||||
download_and_install "$url" "$ext" "$is_windows" "$fallback_url"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
+13
-2
@@ -57,8 +57,10 @@ if ($arch -eq "AMD64") {
|
||||
$tag = $null
|
||||
try {
|
||||
Info "Fetching latest release tag from GitHub API..."
|
||||
$response = Invoke-RestMethod -Uri $API_URL -TimeoutSec 10
|
||||
$response = Invoke-RestMethod -Uri $API_URL -Headers @{ 'User-Agent' = 'install-ocr-ps1' } -TimeoutSec 10
|
||||
if ($response -and $response.assets -and $response.assets.Count -gt 0) {
|
||||
$tag = $response.tag_name
|
||||
}
|
||||
} catch {
|
||||
Warn "Failed to retrieve the latest version from GitHub API. Using fallback version: $FALLBACK_VERSION"
|
||||
$tag = $FALLBACK_VERSION
|
||||
@@ -69,6 +71,7 @@ if (-not $tag) {
|
||||
}
|
||||
|
||||
$downloadUrl = "https://github.com/$REPO/releases/download/$tag/$assetName"
|
||||
$fallbackUrl = "https://github.com/$REPO/releases/download/$FALLBACK_VERSION/$assetName"
|
||||
Info "Resolved download URL: $downloadUrl"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -85,8 +88,16 @@ $destFile = Join-Path $INSTALL_DIR "ocr.exe"
|
||||
|
||||
try {
|
||||
Info "Downloading binary..."
|
||||
# Invoke-WebRequest를 사용해 다운로드 진행
|
||||
try {
|
||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $tempFile -UseBasicParsing
|
||||
} catch {
|
||||
if ($downloadUrl -ne $fallbackUrl) {
|
||||
Warn "Primary download failed. Retrying with fallback version ($FALLBACK_VERSION): $fallbackUrl"
|
||||
Invoke-WebRequest -Uri $fallbackUrl -OutFile $tempFile -UseBasicParsing
|
||||
} else {
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
# 다운로드 완료 후 복사
|
||||
if (Test-Path $destFile) {
|
||||
|
||||
+9
-3
@@ -71,9 +71,9 @@ get_latest_tag() {
|
||||
local json tag
|
||||
info "GitHub API에서 Open Code Review 최신 릴리즈 정보를 가져오는 중..."
|
||||
|
||||
if json=$(curl -fsSL --connect-timeout 10 "${API_URL}" 2>/dev/null); then
|
||||
if json=$(curl -fsSL -H "User-Agent: install-ocr-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null); then
|
||||
if command -v jq &>/dev/null; then
|
||||
tag=$(echo "$json" | jq -r '.tag_name')
|
||||
tag=$(echo "$json" | jq -r 'select((.assets | length) > 0) | .tag_name')
|
||||
else
|
||||
# jq가 없는 경우 grep & sed 사용
|
||||
tag=$(echo "$json" | grep '"tag_name":' | head -n 1 | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/')
|
||||
@@ -92,7 +92,7 @@ get_latest_tag() {
|
||||
# 메인 설치 함수
|
||||
# ────────────────────────────────────────────
|
||||
main() {
|
||||
local asset_name tag url tmpdir dest_file
|
||||
local asset_name tag url fallback_url tmpdir dest_file
|
||||
|
||||
asset_name="$(detect_platform)"
|
||||
info "감지된 플랫폼 에셋: $asset_name"
|
||||
@@ -101,6 +101,7 @@ main() {
|
||||
info "적용할 버전 태그: $tag"
|
||||
|
||||
url="https://github.com/${REPO}/releases/download/${tag}/${asset_name}"
|
||||
fallback_url="https://github.com/${REPO}/releases/download/${FALLBACK_VERSION}/${asset_name}"
|
||||
|
||||
# 임시 디렉토리 생성
|
||||
tmpdir="$(mktemp -d)"
|
||||
@@ -110,8 +111,13 @@ main() {
|
||||
|
||||
info "바이너리 다운로드 중: $url"
|
||||
if ! curl -fsSL --progress-bar -o "$dest_file" "$url"; then
|
||||
if [[ "$tag" != "$FALLBACK_VERSION" ]]; then
|
||||
warn "최신 버전(${tag}) 다운로드 실패. 검증된 폴백 버전(${FALLBACK_VERSION})으로 재시도합니다: $fallback_url"
|
||||
curl -fsSL --progress-bar -o "$dest_file" "$fallback_url" || error "다운로드 실패: $fallback_url"
|
||||
else
|
||||
error "다운로드 실패: $url"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 설치 디렉토리 확보
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
|
||||
+28
-10
@@ -52,6 +52,7 @@ function Write-Err { param([string]$msg) Write-Host "[ERROR] $msg" -Foregrou
|
||||
# ────────────────────────────────────────────
|
||||
$REPO = "tsl0922/ttyd"
|
||||
$API_URL = "https://api.github.com/repos/$REPO/releases/latest"
|
||||
$FALLBACK_TAG = "1.7.7"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
# 메인 설치 프로세스
|
||||
@@ -59,24 +60,32 @@ $API_URL = "https://api.github.com/repos/$REPO/releases/latest"
|
||||
|
||||
# 1) GitHub 최신 릴리스 정보 획득
|
||||
Write-Info "Fetching latest ttyd release information from GitHub API..."
|
||||
$release = $null
|
||||
$tagName = $FALLBACK_TAG
|
||||
try {
|
||||
$release = Invoke-RestMethod -Uri $API_URL -UseBasicParsing -Headers @{ 'User-Agent' = 'install-ttyd-ps1' }
|
||||
$release = Invoke-RestMethod -Uri $API_URL -UseBasicParsing -Headers @{ 'User-Agent' = 'install-ttyd-ps1' } -TimeoutSec 15
|
||||
if ($release -and $release.tag_name -and $release.assets -and $release.assets.Count -gt 0) {
|
||||
$tagName = $release.tag_name
|
||||
}
|
||||
} catch {
|
||||
Write-Err "GitHub API call failed: $_"
|
||||
Write-Warn "GitHub API call failed: $_. Using fallback tag: $FALLBACK_TAG"
|
||||
}
|
||||
|
||||
$tagName = $release.tag_name
|
||||
Write-Info "Latest ttyd version confirmed: $tagName"
|
||||
Write-Info "Target ttyd version: $tagName"
|
||||
|
||||
# 2) ttyd.win32.exe 에셋 탐색
|
||||
$assetName = "ttyd.win32.exe"
|
||||
$asset = $release.assets | Where-Object { $_.name -eq $assetName } | Select-Object -First 1
|
||||
|
||||
if (-not $asset) {
|
||||
Write-Err "Could not find '$assetName' binary in release $tagName."
|
||||
$asset = $null
|
||||
if ($release -and $release.assets) {
|
||||
$asset = $release.assets | Where-Object { $_.name -eq $assetName } | Select-Object -First 1
|
||||
}
|
||||
|
||||
$downloadUrl = $asset.browser_download_url
|
||||
if ($asset -and $asset.browser_download_url) {
|
||||
$downloadUrl = $asset.browser_download_url
|
||||
} else {
|
||||
$downloadUrl = "https://github.com/$REPO/releases/download/$tagName/$assetName"
|
||||
}
|
||||
$fallbackUrl = "https://github.com/$REPO/releases/download/$FALLBACK_TAG/$assetName"
|
||||
$destExeName = "ttyd.exe"
|
||||
|
||||
# 3) 다운로드 및 디렉토리 생성
|
||||
@@ -92,8 +101,17 @@ $tmpFilePath = Join-Path $tmpDir $assetName
|
||||
|
||||
try {
|
||||
Write-Info "Downloading binary: $downloadUrl"
|
||||
$ProgressPreference = 'SilentlyContinue' # 다운로드 진행 바 숨김으로 속도 향상
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
try {
|
||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $tmpFilePath -UseBasicParsing
|
||||
} catch {
|
||||
if ($downloadUrl -ne $fallbackUrl) {
|
||||
Write-Warn "Primary download failed. Retrying with fallback version ($FALLBACK_TAG): $fallbackUrl"
|
||||
Invoke-WebRequest -Uri $fallbackUrl -OutFile $tmpFilePath -UseBasicParsing
|
||||
} else {
|
||||
throw
|
||||
}
|
||||
}
|
||||
$ProgressPreference = 'Continue'
|
||||
|
||||
Write-Info "Deploying binary to install path: $destPath"
|
||||
|
||||
+27
-10
@@ -17,6 +17,7 @@ set -euo pipefail
|
||||
# ────────────────────────────────────────────
|
||||
REPO="tsl0922/ttyd"
|
||||
API_URL="https://api.github.com/repos/${REPO}/releases/latest"
|
||||
FALLBACK_TAG="1.7.7"
|
||||
INSTALL_DIR="${HOME}/.local/bin"
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -53,20 +54,24 @@ for cmd in curl uname; do
|
||||
command -v "$cmd" &>/dev/null || error "'$cmd' 명령어가 필요합니다."
|
||||
done
|
||||
|
||||
# Fallback: jq가 없을 경우 python3를 사용해 JSON 정보 분석
|
||||
# Fallback: jq가 없을 경우 python3 또는 grep을 사용해 JSON 정보 분석
|
||||
if command -v jq &>/dev/null; then
|
||||
_json_latest_tag() {
|
||||
jq -r '.tag_name'
|
||||
jq -r 'select((.assets | length) > 0) | .tag_name'
|
||||
}
|
||||
else
|
||||
command -v python3 &>/dev/null || error "'jq' 또는 'python3' 명령어가 설치되어 있어야 합니다."
|
||||
elif command -v python3 &>/dev/null; then
|
||||
_json_latest_tag() {
|
||||
python3 -c "
|
||||
import sys, json
|
||||
data = json.load(sys.stdin)
|
||||
print(data.get('tag_name', ''))
|
||||
if data.get('assets'):
|
||||
print(data.get('tag_name', ''))
|
||||
"
|
||||
}
|
||||
else
|
||||
_json_latest_tag() {
|
||||
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||
}
|
||||
fi
|
||||
|
||||
# ────────────────────────────────────────────
|
||||
@@ -121,12 +126,15 @@ detect_platform() {
|
||||
get_latest_release_tag() {
|
||||
info "GitHub API를 통해 ttyd 최신 릴리스 버전을 가져오는 중..."
|
||||
|
||||
local release_json tag
|
||||
release_json="$(curl -fsSL "${API_URL}")" || error "GitHub API 호출에 실패했습니다."
|
||||
local release_json="" tag=""
|
||||
release_json="$(curl -fsSL -H "User-Agent: install-ttyd-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null)" || true
|
||||
|
||||
tag="$(echo "$release_json" | _json_latest_tag)"
|
||||
if [[ -n "$release_json" ]]; then
|
||||
tag="$(echo "$release_json" | _json_latest_tag 2>/dev/null || true)"
|
||||
fi
|
||||
if [[ -z "$tag" || "$tag" == "null" ]]; then
|
||||
error "최신 릴리스 태그를 확인하는 데 실패했습니다."
|
||||
warn "최신 릴리스 태그 조회 실패. 검증된 폴백 버전(${FALLBACK_TAG})을 사용합니다."
|
||||
tag="${FALLBACK_TAG}"
|
||||
fi
|
||||
echo "$tag"
|
||||
}
|
||||
@@ -156,11 +164,12 @@ main() {
|
||||
fi
|
||||
|
||||
# 2) Linux / Windows Bash (바이너리 직접 설치 방식)
|
||||
local tag download_url
|
||||
local tag download_url fallback_url
|
||||
tag="$(get_latest_release_tag)"
|
||||
info "최신 버전 감지: $tag"
|
||||
|
||||
download_url="https://github.com/tsl0922/ttyd/releases/download/${tag}/${asset_name}"
|
||||
fallback_url="https://github.com/tsl0922/ttyd/releases/download/${FALLBACK_TAG}/${asset_name}"
|
||||
|
||||
# 설치 디렉토리 생성
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
@@ -176,9 +185,17 @@ main() {
|
||||
|
||||
info "바이너리 다운로드 중: $download_url"
|
||||
if ! curl -fsSL "$download_url" -o "$tmp_file"; then
|
||||
if [[ "$tag" != "$FALLBACK_TAG" ]]; then
|
||||
warn "다운로드 실패. 폴백 버전(${FALLBACK_TAG})으로 재시도합니다: $fallback_url"
|
||||
if ! curl -fsSL "$fallback_url" -o "$tmp_file"; then
|
||||
rm -rf "$tmp_dir"
|
||||
error "바이너리 다운로드에 실패했습니다. URL: $fallback_url"
|
||||
fi
|
||||
else
|
||||
rm -rf "$tmp_dir"
|
||||
error "바이너리 다운로드에 실패했습니다. URL: $download_url"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "설치 경로로 복사 중: $dest_file"
|
||||
mv "$tmp_file" "$dest_file"
|
||||
|
||||
Reference in new issue
Block a user