전체 설치 스크립트 GitHub 릴리스 에셋 검증 및 폴백 다운로드 방어 로직 적용
This commit is contained in:
1 parent
5a67e7bbcf
commit
b41d2f68f3
21 files changed
+504
-153
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
|
$tag = $null
|
||||||
try {
|
try {
|
||||||
Info "Fetching latest release tag from GitHub API..."
|
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
|
$tag = $response.tag_name
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Warn "Failed to retrieve the latest version from GitHub API. Using fallback version: $FALLBACK_VERSION"
|
Warn "Failed to retrieve the latest version from GitHub API. Using fallback version: $FALLBACK_VERSION"
|
||||||
$tag = $FALLBACK_VERSION
|
$tag = $FALLBACK_VERSION
|
||||||
@@ -63,6 +65,7 @@ if (-not $tag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$downloadUrl = "https://github.com/$REPO/releases/download/$tag/$assetName"
|
$downloadUrl = "https://github.com/$REPO/releases/download/$tag/$assetName"
|
||||||
|
$fallbackUrl = "https://github.com/$REPO/releases/download/$FALLBACK_VERSION/$assetName"
|
||||||
Info "Resolved download URL: $downloadUrl"
|
Info "Resolved download URL: $downloadUrl"
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -80,7 +83,16 @@ $destFile = Join-Path $INSTALL_DIR "all-smi.exe"
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Info "Downloading binary archive..."
|
Info "Downloading binary archive..."
|
||||||
|
try {
|
||||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $tempZip -UseBasicParsing
|
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) {
|
if (Test-Path $tempExtractDir) {
|
||||||
Remove-Item $tempExtractDir -Recurse -Force
|
Remove-Item $tempExtractDir -Recurse -Force
|
||||||
|
|||||||
+9
-3
@@ -71,9 +71,9 @@ get_latest_tag() {
|
|||||||
local json tag
|
local json tag
|
||||||
info "GitHub API에서 all-smi 최신 릴리즈 정보를 가져오는 중..."
|
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
|
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
|
else
|
||||||
# jq가 없는 경우 grep & sed 사용
|
# jq가 없는 경우 grep & sed 사용
|
||||||
tag=$(echo "$json" | grep '"tag_name":' | head -n 1 | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/')
|
tag=$(echo "$json" | grep '"tag_name":' | head -n 1 | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/')
|
||||||
@@ -92,7 +92,7 @@ get_latest_tag() {
|
|||||||
# 메인 설치 함수
|
# 메인 설치 함수
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
main() {
|
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)"
|
platform_info="$(detect_platform)"
|
||||||
asset_name="${platform_info%%:*}"
|
asset_name="${platform_info%%:*}"
|
||||||
@@ -104,6 +104,7 @@ main() {
|
|||||||
info "적용할 버전 태그: $tag"
|
info "적용할 버전 태그: $tag"
|
||||||
|
|
||||||
url="https://github.com/${REPO}/releases/download/${tag}/${asset_name}"
|
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)"
|
tmpdir="$(mktemp -d)"
|
||||||
@@ -113,8 +114,13 @@ main() {
|
|||||||
|
|
||||||
info "바이너리 아카이브 다운로드 중: $url"
|
info "바이너리 아카이브 다운로드 중: $url"
|
||||||
if ! curl -fsSL --progress-bar -o "$archive_file" "$url"; then
|
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"
|
error "다운로드 실패: $url"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
info "압축 해제 중..."
|
info "압축 해제 중..."
|
||||||
case "$format" in
|
case "$format" in
|
||||||
|
|||||||
+28
-15
@@ -1,4 +1,4 @@
|
|||||||
#Requires -Version 5.1
|
#Requires -Version 5.1
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Installs bottom(btm) process monitor from GitHub Nightly releases.
|
Installs bottom(btm) process monitor from GitHub Nightly releases.
|
||||||
@@ -48,6 +48,7 @@ $ErrorActionPreference = 'Stop'
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
$REPO = "ClementTsang/bottom"
|
$REPO = "ClementTsang/bottom"
|
||||||
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
||||||
|
$FALLBACK_TAG = "0.12.3"
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
# Utility functions
|
# Utility functions
|
||||||
@@ -98,25 +99,26 @@ function Get-Platform {
|
|||||||
# Get latest Nightly release tag
|
# Get latest Nightly release tag
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
function Get-LatestNightlyTag {
|
function Get-LatestNightlyTag {
|
||||||
Write-Info "Fetching latest Nightly release from GitHub API..."
|
Write-Info "Fetching latest release from GitHub API..."
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
||||||
-Headers @{ 'User-Agent' = 'install-bottom-ps1' }
|
-Headers @{ 'User-Agent' = 'install-bottom-ps1' } -TimeoutSec 15
|
||||||
} catch {
|
|
||||||
Write-Err "Failed to call GitHub API: $_"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get first item where prerelease=true and tag_name starts with 'nightly-'
|
|
||||||
$nightly = $releases | Where-Object {
|
$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
|
} | Select-Object -First 1
|
||||||
|
|
||||||
if (-not $nightly) {
|
if ($nightly -and $nightly.tag_name) {
|
||||||
Write-Err "Could not find Nightly release."
|
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
|
# Download, extract & install
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
function Install-Bottom {
|
function Install-Bottom {
|
||||||
param([string]$Url)
|
param([string]$Url, [string]$FallbackUrl)
|
||||||
|
|
||||||
# Create temp directory
|
# Create temp directory
|
||||||
$tmpDir = Join-Path $env:TEMP "bottom_install_$(Get-Random)"
|
$tmpDir = Join-Path $env:TEMP "bottom_install_$(Get-Random)"
|
||||||
@@ -143,13 +145,23 @@ function Install-Bottom {
|
|||||||
|
|
||||||
Write-Info "Downloading: $Url"
|
Write-Info "Downloading: $Url"
|
||||||
try {
|
try {
|
||||||
# Suppress progress bar in PowerShell 5+
|
|
||||||
$ProgressPreference = 'SilentlyContinue'
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
||||||
$ProgressPreference = 'Continue'
|
$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 {
|
} catch {
|
||||||
Write-Err "Download failed: $_"
|
Write-Err "Download failed: $_"
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Write-Err "Download failed: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Write-Info "Extracting..."
|
Write-Info "Extracting..."
|
||||||
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
||||||
@@ -220,10 +232,11 @@ function Main {
|
|||||||
Write-Info "Detected platform: $triple"
|
Write-Info "Detected platform: $triple"
|
||||||
|
|
||||||
$tag = Get-LatestNightlyTag
|
$tag = Get-LatestNightlyTag
|
||||||
Write-Info "Latest Nightly tag: $tag"
|
Write-Info "Release tag: $tag"
|
||||||
|
|
||||||
$url = Get-DownloadUrl -Tag $tag -Triple $triple
|
$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) {
|
if ($AddToPath) {
|
||||||
Add-ToUserPath -Dir $InstallDir
|
Add-ToUserPath -Dir $InstallDir
|
||||||
|
|||||||
+33
-15
@@ -18,6 +18,7 @@ set -euo pipefail
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
REPO="ClementTsang/bottom"
|
REPO="ClementTsang/bottom"
|
||||||
API_URL="https://api.github.com/repos/${REPO}/releases"
|
API_URL="https://api.github.com/repos/${REPO}/releases"
|
||||||
|
FALLBACK_TAG="0.12.3"
|
||||||
INSTALL_DIR="${HOME}/.local/bin"
|
INSTALL_DIR="${HOME}/.local/bin"
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -35,23 +36,26 @@ for cmd in curl uname; do
|
|||||||
command -v "$cmd" &>/dev/null || error "'$cmd' 명령어가 필요합니다."
|
command -v "$cmd" &>/dev/null || error "'$cmd' 명령어가 필요합니다."
|
||||||
done
|
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
|
if command -v jq &>/dev/null; then
|
||||||
_json_nightly_tag() {
|
_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
|
elif command -v python3 &>/dev/null; then
|
||||||
command -v python3 &>/dev/null || error "'jq' or 'python3' is required."
|
|
||||||
_json_nightly_tag() {
|
_json_nightly_tag() {
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import sys, json
|
import sys, json
|
||||||
data = json.load(sys.stdin)
|
data = json.load(sys.stdin)
|
||||||
for r in data:
|
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'])
|
print(r['tag_name'])
|
||||||
break
|
break
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
_json_nightly_tag() {
|
||||||
|
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -131,15 +135,19 @@ detect_platform() {
|
|||||||
# Get latest Nightly release tag
|
# Get latest Nightly release tag
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
get_latest_nightly_tag() {
|
get_latest_nightly_tag() {
|
||||||
info "Fetching latest Nightly release from GitHub API..."
|
info "Fetching latest release from GitHub API..."
|
||||||
|
|
||||||
local releases
|
local releases="" tag=""
|
||||||
releases="$(curl -fsSL "${API_URL}")" || error "Failed to call GitHub API."
|
releases="$(curl -fsSL -H "User-Agent: install-bottom-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null)" || true
|
||||||
|
|
||||||
local tag
|
if [[ -n "$releases" ]]; then
|
||||||
tag="$(echo "$releases" | _json_nightly_tag)"
|
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"
|
echo "$tag"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +169,7 @@ download_and_install() {
|
|||||||
local url="$1"
|
local url="$1"
|
||||||
local ext="$2" # tar.gz | zip
|
local ext="$2" # tar.gz | zip
|
||||||
local is_windows="${3:-false}"
|
local is_windows="${3:-false}"
|
||||||
|
local fallback_url="${4:-}"
|
||||||
|
|
||||||
local tmpdir
|
local tmpdir
|
||||||
tmpdir="$(mktemp -d)"
|
tmpdir="$(mktemp -d)"
|
||||||
@@ -170,8 +179,15 @@ download_and_install() {
|
|||||||
filename="${url##*/}"
|
filename="${url##*/}"
|
||||||
|
|
||||||
info "Downloading: $url"
|
info "Downloading: $url"
|
||||||
curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url" \
|
if ! curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url"; then
|
||||||
|| error "Download failed: $url"
|
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..."
|
info "Extracting..."
|
||||||
case "$ext" in
|
case "$ext" in
|
||||||
@@ -239,10 +255,12 @@ main() {
|
|||||||
[[ "$triple" == *"windows"* ]] && is_windows="true"
|
[[ "$triple" == *"windows"* ]] && is_windows="true"
|
||||||
|
|
||||||
tag="$(get_latest_nightly_tag)"
|
tag="$(get_latest_nightly_tag)"
|
||||||
info "Latest Nightly tag: $tag"
|
info "Release tag: $tag"
|
||||||
|
|
||||||
url="$(build_download_url "$tag" "$triple" "$ext")"
|
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 "$@"
|
main "$@"
|
||||||
+28
-12
@@ -1,4 +1,4 @@
|
|||||||
#Requires -Version 5.1
|
#Requires -Version 5.1
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Installs ctop (container terminal UI) from GitHub releases.
|
Installs ctop (container terminal UI) from GitHub releases.
|
||||||
@@ -49,6 +49,7 @@ $ErrorActionPreference = 'Stop'
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
$REPO = "bcicen/ctop"
|
$REPO = "bcicen/ctop"
|
||||||
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
||||||
|
$FALLBACK_TAG = "v0.7.7"
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
# Utility functions
|
# Utility functions
|
||||||
@@ -106,19 +107,22 @@ function Get-LatestTag {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
||||||
-Headers @{ 'User-Agent' = 'install-ctop-ps1' }
|
-Headers @{ 'User-Agent' = 'install-ctop-ps1' } -TimeoutSec 15
|
||||||
} catch {
|
|
||||||
Write-Err "Failed to call GitHub API: $_"
|
|
||||||
}
|
|
||||||
|
|
||||||
$latest = $releases | Where-Object { $_.prerelease -eq $false } | Select-Object -First 1
|
$latest = $releases | Where-Object {
|
||||||
|
$_.prerelease -eq $false -and $_.assets -and $_.assets.Count -gt 0
|
||||||
if (-not $latest) {
|
} | Select-Object -First 1
|
||||||
Write-Err "Could not find latest release."
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ($latest -and $latest.tag_name) {
|
||||||
return $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
|
||||||
|
}
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
# Build download URL
|
# Build download URL
|
||||||
@@ -135,7 +139,7 @@ function Get-DownloadUrl {
|
|||||||
# Download & install (raw binary — no archive extraction needed)
|
# Download & install (raw binary — no archive extraction needed)
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
function Install-Ctop {
|
function Install-Ctop {
|
||||||
param([string]$Url)
|
param([string]$Url, [string]$FallbackUrl)
|
||||||
|
|
||||||
$tmpDir = Join-Path $env:TEMP "ctop_install_$(Get-Random)"
|
$tmpDir = Join-Path $env:TEMP "ctop_install_$(Get-Random)"
|
||||||
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
||||||
@@ -148,9 +152,20 @@ function Install-Ctop {
|
|||||||
$ProgressPreference = 'SilentlyContinue'
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
Invoke-WebRequest -Uri $Url -OutFile $binPath -UseBasicParsing
|
Invoke-WebRequest -Uri $Url -OutFile $binPath -UseBasicParsing
|
||||||
$ProgressPreference = 'Continue'
|
$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 {
|
} catch {
|
||||||
Write-Err "Download failed: $_"
|
Write-Err "Download failed: $_"
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Write-Err "Download failed: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Create install directory
|
# Create install directory
|
||||||
if (-not (Test-Path $InstallDir)) {
|
if (-not (Test-Path $InstallDir)) {
|
||||||
@@ -210,7 +225,8 @@ function Main {
|
|||||||
Write-Info "Latest release: $tag"
|
Write-Info "Latest release: $tag"
|
||||||
|
|
||||||
$url = Get-DownloadUrl -Tag $tag -Platform $platform
|
$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) {
|
if ($AddToPath) {
|
||||||
Add-ToUserPath -Dir $InstallDir
|
Add-ToUserPath -Dir $InstallDir
|
||||||
|
|||||||
+31
-13
@@ -16,6 +16,7 @@ set -euo pipefail
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
REPO="bcicen/ctop"
|
REPO="bcicen/ctop"
|
||||||
API_URL="https://api.github.com/repos/${REPO}/releases"
|
API_URL="https://api.github.com/repos/${REPO}/releases"
|
||||||
|
FALLBACK_TAG="v0.7.7"
|
||||||
INSTALL_DIR="${HOME}/.local/bin"
|
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."
|
command -v "$cmd" &>/dev/null || error "'$cmd' command is required."
|
||||||
done
|
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
|
if command -v jq &>/dev/null; then
|
||||||
_json_latest_tag() {
|
_json_latest_tag() {
|
||||||
jq -r '[.[] | select(.prerelease==false)] | .[0].tag_name'
|
jq -r '[.[] | select(.prerelease==false and ((.assets | length) > 0))] | .[0].tag_name'
|
||||||
}
|
}
|
||||||
else
|
elif command -v python3 &>/dev/null; then
|
||||||
command -v python3 &>/dev/null || error "'jq' or 'python3' is required."
|
|
||||||
_json_latest_tag() {
|
_json_latest_tag() {
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import sys, json
|
import sys, json
|
||||||
data = json.load(sys.stdin)
|
data = json.load(sys.stdin)
|
||||||
for r in data:
|
for r in data:
|
||||||
if not r.get('prerelease'):
|
if not r.get('prerelease') and r.get('assets'):
|
||||||
print(r['tag_name'])
|
print(r['tag_name'])
|
||||||
break
|
break
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
_json_latest_tag() {
|
||||||
|
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -118,13 +122,17 @@ detect_platform() {
|
|||||||
get_latest_tag() {
|
get_latest_tag() {
|
||||||
info "Fetching latest release from GitHub API..."
|
info "Fetching latest release from GitHub API..."
|
||||||
|
|
||||||
local releases
|
local releases="" tag=""
|
||||||
releases="$(curl -fsSL "${API_URL}")" || error "Failed to call GitHub API."
|
releases="$(curl -fsSL -H "User-Agent: install-ctop-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null)" || true
|
||||||
|
|
||||||
local tag
|
if [[ -n "$releases" ]]; then
|
||||||
tag="$(echo "$releases" | _json_latest_tag)"
|
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"
|
echo "$tag"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +154,7 @@ build_download_url() {
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
download_and_install() {
|
download_and_install() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
|
local fallback_url="${2:-}"
|
||||||
|
|
||||||
local tmpdir
|
local tmpdir
|
||||||
tmpdir="$(mktemp -d)"
|
tmpdir="$(mktemp -d)"
|
||||||
@@ -155,8 +164,15 @@ download_and_install() {
|
|||||||
filename="${url##*/}"
|
filename="${url##*/}"
|
||||||
|
|
||||||
info "Downloading: $url"
|
info "Downloading: $url"
|
||||||
curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url" \
|
if ! curl -fsSL --progress-bar -o "${tmpdir}/${filename}" "$url"; then
|
||||||
|| error "Download failed: $url"
|
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
|
# ctop provides raw binaries (not archives), so skip extraction
|
||||||
local bin_src="${tmpdir}/${filename}"
|
local bin_src="${tmpdir}/${filename}"
|
||||||
@@ -194,7 +210,9 @@ main() {
|
|||||||
info "Latest release: $tag"
|
info "Latest release: $tag"
|
||||||
|
|
||||||
url="$(build_download_url "$tag" "$platform")"
|
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 "$@"
|
main "$@"
|
||||||
+14
-2
@@ -127,7 +127,7 @@ function Get-DownloadUrl {
|
|||||||
# Download, extract & install
|
# Download, extract & install
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
function Install-Dua {
|
function Install-Dua {
|
||||||
param([string]$Url)
|
param([string]$Url, [string]$FallbackUrl)
|
||||||
|
|
||||||
$tmpDir = Join-Path $env:TEMP "dua_install_$(Get-Random)"
|
$tmpDir = Join-Path $env:TEMP "dua_install_$(Get-Random)"
|
||||||
New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null
|
New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null
|
||||||
@@ -141,8 +141,19 @@ function Install-Dua {
|
|||||||
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
||||||
$ProgressPreference = 'Continue'
|
$ProgressPreference = 'Continue'
|
||||||
} catch {
|
} 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 : $_"
|
ErrExit "Download failed from $Url : $_"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Info "Extracting archive..."
|
Info "Extracting archive..."
|
||||||
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
||||||
@@ -218,7 +229,8 @@ function Main {
|
|||||||
Info "Release tag: $tag"
|
Info "Release tag: $tag"
|
||||||
|
|
||||||
$url = Get-DownloadUrl -Tag $tag -Triple $triple
|
$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) {
|
if ($AddToPath) {
|
||||||
Add-ToUserPath -Dir $InstallDir
|
Add-ToUserPath -Dir $InstallDir
|
||||||
|
|||||||
+10
-1
@@ -145,13 +145,22 @@ install_from_github() {
|
|||||||
tag="$(get_latest_tag)"
|
tag="$(get_latest_tag)"
|
||||||
local filename="dua-${tag}-${target}.tar.gz"
|
local filename="dua-${tag}-${target}.tar.gz"
|
||||||
local download_url="https://github.com/${REPO}/releases/download/${tag}/${filename}"
|
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"
|
info "Downloading: $download_url"
|
||||||
TMPDIR="$(mktemp -d)"
|
TMPDIR="$(mktemp -d)"
|
||||||
trap '[[ -d "${TMPDIR:-}" ]] && rm -rf "$TMPDIR"' EXIT
|
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"
|
error "Download failed: $download_url"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
info "Extracting..."
|
info "Extracting..."
|
||||||
tar -xzf "${TMPDIR}/${filename}" -C "$TMPDIR"
|
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"
|
$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"
|
$HELIX_CONFIG_DIR = Join-Path $env:APPDATA "helix"
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -76,27 +77,37 @@ function Main {
|
|||||||
|
|
||||||
# 2) GitHub 최신 릴리스 정보 획득
|
# 2) GitHub 최신 릴리스 정보 획득
|
||||||
Write-Info "Fetching latest Helix release information from GitHub API..."
|
Write-Info "Fetching latest Helix release information from GitHub API..."
|
||||||
|
$release = $null
|
||||||
|
$tagName = $FALLBACK_TAG
|
||||||
try {
|
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 {
|
} 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', ''
|
$version = $tagName -replace '^v', ''
|
||||||
Write-Info "Latest Helix version confirmed: $tagName"
|
Write-Info "Target Helix version: $tagName"
|
||||||
|
|
||||||
# 3) 윈도우 x86_64용 zip 파일 에셋 탐색
|
# 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
|
$asset = $release.assets | Where-Object { $_.name -like "*-x86_64-windows.zip" } | Select-Object -First 1
|
||||||
|
}
|
||||||
if (-not $asset) {
|
if (-not $asset) {
|
||||||
# 에셋 조회가 되지 않을 경우 릴리스 패턴에 맞추어 다운로드 URL 직접 빌드
|
|
||||||
$zipName = "helix-${version}-x86_64-windows.zip"
|
$zipName = "helix-${version}-x86_64-windows.zip"
|
||||||
$downloadUrl = "https://github.com/$REPO/releases/download/$tagName/$zipName"
|
$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 {
|
} else {
|
||||||
$zipName = $asset.name
|
$zipName = $asset.name
|
||||||
$downloadUrl = $asset.browser_download_url
|
$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) 임시 작업 디렉토리 생성 및 아카이브 다운로드
|
# 4) 임시 작업 디렉토리 생성 및 아카이브 다운로드
|
||||||
$tmpDir = Join-Path $env:TEMP "helix_install_$(Get-Random)"
|
$tmpDir = Join-Path $env:TEMP "helix_install_$(Get-Random)"
|
||||||
@@ -105,8 +116,17 @@ function Main {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Write-Info "Downloading archive: $downloadUrl"
|
Write-Info "Downloading archive: $downloadUrl"
|
||||||
$ProgressPreference = 'SilentlyContinue' # 다운로드 속도 향상을 위해 진행바 숨김
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
try {
|
||||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $tmpZipPath -UseBasicParsing
|
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'
|
$ProgressPreference = 'Continue'
|
||||||
|
|
||||||
# 5) 압축 해제
|
# 5) 압축 해제
|
||||||
|
|||||||
+33
-10
@@ -14,7 +14,8 @@ set -euo pipefail
|
|||||||
# 상수 정의
|
# 상수 정의
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
REPO="helix-editor/helix"
|
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"
|
INSTALL_DIR="${HOME}/.local/bin"
|
||||||
HELIX_CONFIG_DIR="${HOME}/.config/helix"
|
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' 명령어가 필요합니다. 먼저 설치해 주세요."
|
command -v "$cmd" &>/dev/null || error "'$cmd' 명령어가 필요합니다. 먼저 설치해 주세요."
|
||||||
done
|
done
|
||||||
|
|
||||||
# Fallback: jq가 없을 경우 python3를 사용해 JSON 분석
|
# Fallback: jq가 없을 경우 python3 또는 grep을 사용해 JSON 분석
|
||||||
if command -v jq &>/dev/null; then
|
if command -v jq &>/dev/null; then
|
||||||
_json_latest_tag() {
|
_json_latest_tag() {
|
||||||
jq -r '.tag_name'
|
jq -r '[.[] | select(.prerelease==false and ((.assets | length) > 0))] | .[0].tag_name'
|
||||||
}
|
}
|
||||||
else
|
elif command -v python3 &>/dev/null; then
|
||||||
command -v python3 &>/dev/null || error "'jq' 또는 'python3' 명령어가 설치되어 있어야 합니다."
|
|
||||||
_json_latest_tag() {
|
_json_latest_tag() {
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import sys, json
|
import sys, json
|
||||||
data = json.load(sys.stdin)
|
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
|
fi
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -93,12 +100,15 @@ detect_platform() {
|
|||||||
get_latest_release_tag() {
|
get_latest_release_tag() {
|
||||||
info "GitHub API를 통해 Helix 최신 릴리스 버전을 조회하는 중..."
|
info "GitHub API를 통해 Helix 최신 릴리스 버전을 조회하는 중..."
|
||||||
|
|
||||||
local release_json tag
|
local release_json="" tag=""
|
||||||
release_json="$(curl -fsSL "${API_URL}")" || error "GitHub API 호출에 실패했습니다."
|
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
|
if [[ -z "$tag" || "$tag" == "null" ]]; then
|
||||||
error "최신 릴리스 태그를 확인하는 데 실패했습니다."
|
warn "최신 릴리스 태그 조회 실패. 검증된 폴백 버전(${FALLBACK_TAG})을 사용합니다."
|
||||||
|
tag="${FALLBACK_TAG}"
|
||||||
fi
|
fi
|
||||||
echo "$tag"
|
echo "$tag"
|
||||||
}
|
}
|
||||||
@@ -126,10 +136,23 @@ main() {
|
|||||||
local tmp_archive="${tmp_dir}/${archive_name}"
|
local tmp_archive="${tmp_dir}/${archive_name}"
|
||||||
|
|
||||||
info "아카이브 다운로드 중: $download_url"
|
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
|
if ! curl -fsSL "$download_url" -o "$tmp_archive"; then
|
||||||
rm -rf "$tmp_dir"
|
rm -rf "$tmp_dir"
|
||||||
error "바이너리 다운로드에 실패했습니다. URL: $download_url"
|
error "바이너리 다운로드에 실패했습니다. URL: $download_url"
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
rm -rf "$tmp_dir"
|
||||||
|
error "바이너리 다운로드에 실패했습니다. URL: $download_url"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
info "압축 해제 중..."
|
info "압축 해제 중..."
|
||||||
tar -xf "$tmp_archive" -C "$tmp_dir"
|
tar -xf "$tmp_archive" -C "$tmp_dir"
|
||||||
|
|||||||
+27
-11
@@ -48,6 +48,7 @@ $ErrorActionPreference = 'Stop'
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
$REPO = "jesseduffield/lazydocker"
|
$REPO = "jesseduffield/lazydocker"
|
||||||
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
||||||
|
$FALLBACK_TAG = "v0.25.2"
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
# Utility functions
|
# Utility functions
|
||||||
@@ -96,19 +97,22 @@ function Get-LatestTag {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
||||||
-Headers @{ 'User-Agent' = 'install-lazydocker-ps1' }
|
-Headers @{ 'User-Agent' = 'install-lazydocker-ps1' } -TimeoutSec 15
|
||||||
} catch {
|
|
||||||
Write-Err "Failed to call GitHub API: $_"
|
|
||||||
}
|
|
||||||
|
|
||||||
$latest = $releases | Where-Object { $_.prerelease -eq $false } | Select-Object -First 1
|
$latest = $releases | Where-Object {
|
||||||
|
$_.prerelease -eq $false -and $_.assets -and $_.assets.Count -gt 0
|
||||||
if (-not $latest) {
|
} | Select-Object -First 1
|
||||||
Write-Err "Could not find latest release."
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ($latest -and $latest.tag_name) {
|
||||||
return $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
|
||||||
|
}
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
# Build download URL
|
# Build download URL
|
||||||
@@ -124,7 +128,7 @@ function Get-DownloadUrl {
|
|||||||
# Download, extract & install
|
# Download, extract & install
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
function Install-Lazydocker {
|
function Install-Lazydocker {
|
||||||
param([string]$Url)
|
param([string]$Url, [string]$FallbackUrl)
|
||||||
|
|
||||||
$tmpDir = Join-Path $env:TEMP "lazydocker_install_$(Get-Random)"
|
$tmpDir = Join-Path $env:TEMP "lazydocker_install_$(Get-Random)"
|
||||||
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
||||||
@@ -137,9 +141,20 @@ function Install-Lazydocker {
|
|||||||
$ProgressPreference = 'SilentlyContinue'
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
||||||
$ProgressPreference = 'Continue'
|
$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 {
|
} catch {
|
||||||
Write-Err "Download failed: $_"
|
Write-Err "Download failed: $_"
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Write-Err "Download failed: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Write-Info "Extracting..."
|
Write-Info "Extracting..."
|
||||||
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
||||||
@@ -223,7 +238,8 @@ function Main {
|
|||||||
Write-Info "Latest release: $tag"
|
Write-Info "Latest release: $tag"
|
||||||
|
|
||||||
$url = Get-DownloadUrl -Tag $tag -Platform $platform
|
$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) {
|
if ($AddToPath) {
|
||||||
Add-ToUserPath -Dir $InstallDir
|
Add-ToUserPath -Dir $InstallDir
|
||||||
|
|||||||
+30
-12
@@ -16,6 +16,7 @@ set -euo pipefail
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
REPO="jesseduffield/lazydocker"
|
REPO="jesseduffield/lazydocker"
|
||||||
API_URL="https://api.github.com/repos/${REPO}/releases"
|
API_URL="https://api.github.com/repos/${REPO}/releases"
|
||||||
|
FALLBACK_TAG="v0.25.2"
|
||||||
INSTALL_DIR="${HOME}/.local/bin"
|
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."
|
command -v "$cmd" &>/dev/null || error "'$cmd' command is required."
|
||||||
done
|
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
|
if command -v jq &>/dev/null; then
|
||||||
_json_latest_tag() {
|
_json_latest_tag() {
|
||||||
jq -r '[.[] | select(.prerelease==false)] | .[0].tag_name'
|
jq -r '[.[] | select(.prerelease==false and ((.assets | length) > 0))] | .[0].tag_name'
|
||||||
}
|
}
|
||||||
else
|
elif command -v python3 &>/dev/null; then
|
||||||
command -v python3 &>/dev/null || error "'jq' or 'python3' is required."
|
|
||||||
_json_latest_tag() {
|
_json_latest_tag() {
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import sys, json
|
import sys, json
|
||||||
data = json.load(sys.stdin)
|
data = json.load(sys.stdin)
|
||||||
for r in data:
|
for r in data:
|
||||||
if not r.get('prerelease'):
|
if not r.get('prerelease') and r.get('assets'):
|
||||||
print(r['tag_name'])
|
print(r['tag_name'])
|
||||||
break
|
break
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
_json_latest_tag() {
|
||||||
|
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -124,13 +128,17 @@ detect_platform() {
|
|||||||
get_latest_tag() {
|
get_latest_tag() {
|
||||||
info "Fetching latest release from GitHub API..."
|
info "Fetching latest release from GitHub API..."
|
||||||
|
|
||||||
local releases
|
local releases="" tag=""
|
||||||
releases="$(curl -fsSL "${API_URL}")" || error "Failed to call GitHub API."
|
releases="$(curl -fsSL -H "User-Agent: install-lazydocker-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null)" || true
|
||||||
|
|
||||||
local tag
|
if [[ -n "$releases" ]]; then
|
||||||
tag="$(echo "$releases" | _json_latest_tag)"
|
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"
|
echo "$tag"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +161,7 @@ build_download_url() {
|
|||||||
download_and_install() {
|
download_and_install() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
local ext="$2"
|
local ext="$2"
|
||||||
|
local fallback_url="${3:-}"
|
||||||
|
|
||||||
local tmpdir
|
local tmpdir
|
||||||
tmpdir="$(mktemp -d)"
|
tmpdir="$(mktemp -d)"
|
||||||
@@ -162,8 +171,15 @@ download_and_install() {
|
|||||||
filename="${url##*/}"
|
filename="${url##*/}"
|
||||||
|
|
||||||
info "Downloading: $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"
|
error "Download failed: $url"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
info "Extracting..."
|
info "Extracting..."
|
||||||
case "$ext" in
|
case "$ext" in
|
||||||
@@ -248,7 +264,9 @@ main() {
|
|||||||
info "Latest release: $tag"
|
info "Latest release: $tag"
|
||||||
|
|
||||||
url="$(build_download_url "$tag" "$platform" "$ext")"
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+27
-11
@@ -48,6 +48,7 @@ $ErrorActionPreference = 'Stop'
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
$REPO = "jesseduffield/lazygit"
|
$REPO = "jesseduffield/lazygit"
|
||||||
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
$API_URL = "https://api.github.com/repos/$REPO/releases"
|
||||||
|
$FALLBACK_TAG = "v0.61.1"
|
||||||
$GIT_REPO = "git-for-windows/git"
|
$GIT_REPO = "git-for-windows/git"
|
||||||
$GIT_API_URL = "https://api.github.com/repos/$GIT_REPO/releases"
|
$GIT_API_URL = "https://api.github.com/repos/$GIT_REPO/releases"
|
||||||
|
|
||||||
@@ -254,19 +255,22 @@ function Get-LatestTag {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
$releases = Invoke-RestMethod -Uri $API_URL -UseBasicParsing `
|
||||||
-Headers @{ 'User-Agent' = 'install-lazygit-ps1' }
|
-Headers @{ 'User-Agent' = 'install-lazygit-ps1' } -TimeoutSec 15
|
||||||
} catch {
|
|
||||||
Write-Err "Failed to call GitHub API: $_"
|
|
||||||
}
|
|
||||||
|
|
||||||
$latest = $releases | Where-Object { $_.prerelease -eq $false } | Select-Object -First 1
|
$latest = $releases | Where-Object {
|
||||||
|
$_.prerelease -eq $false -and $_.assets -and $_.assets.Count -gt 0
|
||||||
if (-not $latest) {
|
} | Select-Object -First 1
|
||||||
Write-Err "Could not find latest release."
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ($latest -and $latest.tag_name) {
|
||||||
return $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
|
||||||
|
}
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
# Build download URL
|
# Build download URL
|
||||||
@@ -282,7 +286,7 @@ function Get-DownloadUrl {
|
|||||||
# Download, extract & install
|
# Download, extract & install
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
function Install-Lazygit {
|
function Install-Lazygit {
|
||||||
param([string]$Url)
|
param([string]$Url, [string]$FallbackUrl)
|
||||||
|
|
||||||
$tmpDir = Join-Path $env:TEMP "lazygit_install_$(Get-Random)"
|
$tmpDir = Join-Path $env:TEMP "lazygit_install_$(Get-Random)"
|
||||||
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
||||||
@@ -295,9 +299,20 @@ function Install-Lazygit {
|
|||||||
$ProgressPreference = 'SilentlyContinue'
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
Invoke-WebRequest -Uri $Url -OutFile $zipPath -UseBasicParsing
|
||||||
$ProgressPreference = 'Continue'
|
$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 {
|
} catch {
|
||||||
Write-Err "Download failed: $_"
|
Write-Err "Download failed: $_"
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Write-Err "Download failed: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Write-Info "Extracting..."
|
Write-Info "Extracting..."
|
||||||
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
Expand-Archive -Path $zipPath -DestinationPath $tmpDir -Force
|
||||||
@@ -370,7 +385,8 @@ function Main {
|
|||||||
Write-Info "Latest release: $tag"
|
Write-Info "Latest release: $tag"
|
||||||
|
|
||||||
$url = Get-DownloadUrl -Tag $tag -Platform $platform
|
$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) {
|
if ($AddToPath) {
|
||||||
Add-ToUserPath -Dir $InstallDir
|
Add-ToUserPath -Dir $InstallDir
|
||||||
|
|||||||
+30
-17
@@ -17,6 +17,7 @@ set -euo pipefail
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
REPO="jesseduffield/lazygit"
|
REPO="jesseduffield/lazygit"
|
||||||
API_URL="https://api.github.com/repos/${REPO}/releases"
|
API_URL="https://api.github.com/repos/${REPO}/releases"
|
||||||
|
FALLBACK_TAG="v0.61.1"
|
||||||
INSTALL_DIR="${HOME}/.local/bin"
|
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/"
|
command -v brew &>/dev/null || error "Homebrew installation failed. Install it manually: https://brew.sh/"
|
||||||
success "Homebrew installed"
|
success "Homebrew installed"
|
||||||
}
|
}
|
||||||
error() {
|
|
||||||
echo "[ERROR] $*" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
success() { echo "[OK] $*" >&2; }
|
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
# Check for git (required by lazygit)
|
# 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."
|
command -v "$cmd" &>/dev/null || error "'$cmd' command is required."
|
||||||
done
|
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
|
if command -v jq &>/dev/null; then
|
||||||
_json_latest_tag() {
|
_json_latest_tag() {
|
||||||
jq -r '[.[] | select(.prerelease==false)] | .[0].tag_name'
|
jq -r '[.[] | select(.prerelease==false and ((.assets | length) > 0))] | .[0].tag_name'
|
||||||
}
|
}
|
||||||
else
|
elif command -v python3 &>/dev/null; then
|
||||||
command -v python3 &>/dev/null || error "'jq' or 'python3' is required."
|
|
||||||
_json_latest_tag() {
|
_json_latest_tag() {
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import sys, json
|
import sys, json
|
||||||
data = json.load(sys.stdin)
|
data = json.load(sys.stdin)
|
||||||
for r in data:
|
for r in data:
|
||||||
if not r.get('prerelease'):
|
if not r.get('prerelease') and r.get('assets'):
|
||||||
print(r['tag_name'])
|
print(r['tag_name'])
|
||||||
break
|
break
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
_json_latest_tag() {
|
||||||
|
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -205,13 +204,17 @@ detect_platform() {
|
|||||||
get_latest_tag() {
|
get_latest_tag() {
|
||||||
info "Fetching latest release from GitHub API..."
|
info "Fetching latest release from GitHub API..."
|
||||||
|
|
||||||
local releases
|
local releases="" tag=""
|
||||||
releases="$(curl -fsSL "${API_URL}")" || error "Failed to call GitHub API."
|
releases="$(curl -fsSL -H "User-Agent: install-lazygit-sh" --connect-timeout 10 "${API_URL}" 2>/dev/null)" || true
|
||||||
|
|
||||||
local tag
|
if [[ -n "$releases" ]]; then
|
||||||
tag="$(echo "$releases" | _json_latest_tag)"
|
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"
|
echo "$tag"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,6 +237,7 @@ download_and_install() {
|
|||||||
local url="$1"
|
local url="$1"
|
||||||
local ext="$2"
|
local ext="$2"
|
||||||
local is_windows="${3:-false}"
|
local is_windows="${3:-false}"
|
||||||
|
local fallback_url="${4:-}"
|
||||||
|
|
||||||
local tmpdir
|
local tmpdir
|
||||||
tmpdir="$(mktemp -d)"
|
tmpdir="$(mktemp -d)"
|
||||||
@@ -243,8 +247,15 @@ download_and_install() {
|
|||||||
filename="${url##*/}"
|
filename="${url##*/}"
|
||||||
|
|
||||||
info "Downloading: $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"
|
error "Download failed: $url"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
info "Extracting..."
|
info "Extracting..."
|
||||||
case "$ext" in
|
case "$ext" in
|
||||||
@@ -313,7 +324,9 @@ main() {
|
|||||||
info "Latest release: $tag"
|
info "Latest release: $tag"
|
||||||
|
|
||||||
url="$(build_download_url "$tag" "$platform" "$ext")"
|
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 "$@"
|
main "$@"
|
||||||
+13
-2
@@ -57,8 +57,10 @@ if ($arch -eq "AMD64") {
|
|||||||
$tag = $null
|
$tag = $null
|
||||||
try {
|
try {
|
||||||
Info "Fetching latest release tag from GitHub API..."
|
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
|
$tag = $response.tag_name
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Warn "Failed to retrieve the latest version from GitHub API. Using fallback version: $FALLBACK_VERSION"
|
Warn "Failed to retrieve the latest version from GitHub API. Using fallback version: $FALLBACK_VERSION"
|
||||||
$tag = $FALLBACK_VERSION
|
$tag = $FALLBACK_VERSION
|
||||||
@@ -69,6 +71,7 @@ if (-not $tag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$downloadUrl = "https://github.com/$REPO/releases/download/$tag/$assetName"
|
$downloadUrl = "https://github.com/$REPO/releases/download/$tag/$assetName"
|
||||||
|
$fallbackUrl = "https://github.com/$REPO/releases/download/$FALLBACK_VERSION/$assetName"
|
||||||
Info "Resolved download URL: $downloadUrl"
|
Info "Resolved download URL: $downloadUrl"
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -85,8 +88,16 @@ $destFile = Join-Path $INSTALL_DIR "ocr.exe"
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Info "Downloading binary..."
|
Info "Downloading binary..."
|
||||||
# Invoke-WebRequest를 사용해 다운로드 진행
|
try {
|
||||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $tempFile -UseBasicParsing
|
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) {
|
if (Test-Path $destFile) {
|
||||||
|
|||||||
+9
-3
@@ -71,9 +71,9 @@ get_latest_tag() {
|
|||||||
local json tag
|
local json tag
|
||||||
info "GitHub API에서 Open Code Review 최신 릴리즈 정보를 가져오는 중..."
|
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
|
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
|
else
|
||||||
# jq가 없는 경우 grep & sed 사용
|
# jq가 없는 경우 grep & sed 사용
|
||||||
tag=$(echo "$json" | grep '"tag_name":' | head -n 1 | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/')
|
tag=$(echo "$json" | grep '"tag_name":' | head -n 1 | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/')
|
||||||
@@ -92,7 +92,7 @@ get_latest_tag() {
|
|||||||
# 메인 설치 함수
|
# 메인 설치 함수
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
main() {
|
main() {
|
||||||
local asset_name tag url tmpdir dest_file
|
local asset_name tag url fallback_url tmpdir dest_file
|
||||||
|
|
||||||
asset_name="$(detect_platform)"
|
asset_name="$(detect_platform)"
|
||||||
info "감지된 플랫폼 에셋: $asset_name"
|
info "감지된 플랫폼 에셋: $asset_name"
|
||||||
@@ -101,6 +101,7 @@ main() {
|
|||||||
info "적용할 버전 태그: $tag"
|
info "적용할 버전 태그: $tag"
|
||||||
|
|
||||||
url="https://github.com/${REPO}/releases/download/${tag}/${asset_name}"
|
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)"
|
tmpdir="$(mktemp -d)"
|
||||||
@@ -110,8 +111,13 @@ main() {
|
|||||||
|
|
||||||
info "바이너리 다운로드 중: $url"
|
info "바이너리 다운로드 중: $url"
|
||||||
if ! curl -fsSL --progress-bar -o "$dest_file" "$url"; then
|
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"
|
error "다운로드 실패: $url"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# 설치 디렉토리 확보
|
# 설치 디렉토리 확보
|
||||||
mkdir -p "$INSTALL_DIR"
|
mkdir -p "$INSTALL_DIR"
|
||||||
|
|||||||
+26
-8
@@ -52,6 +52,7 @@ function Write-Err { param([string]$msg) Write-Host "[ERROR] $msg" -Foregrou
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
$REPO = "tsl0922/ttyd"
|
$REPO = "tsl0922/ttyd"
|
||||||
$API_URL = "https://api.github.com/repos/$REPO/releases/latest"
|
$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 최신 릴리스 정보 획득
|
# 1) GitHub 최신 릴리스 정보 획득
|
||||||
Write-Info "Fetching latest ttyd release information from GitHub API..."
|
Write-Info "Fetching latest ttyd release information from GitHub API..."
|
||||||
|
$release = $null
|
||||||
|
$tagName = $FALLBACK_TAG
|
||||||
try {
|
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 {
|
} catch {
|
||||||
Write-Err "GitHub API call failed: $_"
|
Write-Warn "GitHub API call failed: $_. Using fallback tag: $FALLBACK_TAG"
|
||||||
}
|
}
|
||||||
|
|
||||||
$tagName = $release.tag_name
|
Write-Info "Target ttyd version: $tagName"
|
||||||
Write-Info "Latest ttyd version confirmed: $tagName"
|
|
||||||
|
|
||||||
# 2) ttyd.win32.exe 에셋 탐색
|
# 2) ttyd.win32.exe 에셋 탐색
|
||||||
$assetName = "ttyd.win32.exe"
|
$assetName = "ttyd.win32.exe"
|
||||||
|
$asset = $null
|
||||||
|
if ($release -and $release.assets) {
|
||||||
$asset = $release.assets | Where-Object { $_.name -eq $assetName } | Select-Object -First 1
|
$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."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($asset -and $asset.browser_download_url) {
|
||||||
$downloadUrl = $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"
|
$destExeName = "ttyd.exe"
|
||||||
|
|
||||||
# 3) 다운로드 및 디렉토리 생성
|
# 3) 다운로드 및 디렉토리 생성
|
||||||
@@ -92,8 +101,17 @@ $tmpFilePath = Join-Path $tmpDir $assetName
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Write-Info "Downloading binary: $downloadUrl"
|
Write-Info "Downloading binary: $downloadUrl"
|
||||||
$ProgressPreference = 'SilentlyContinue' # 다운로드 진행 바 숨김으로 속도 향상
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
try {
|
||||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $tmpFilePath -UseBasicParsing
|
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'
|
$ProgressPreference = 'Continue'
|
||||||
|
|
||||||
Write-Info "Deploying binary to install path: $destPath"
|
Write-Info "Deploying binary to install path: $destPath"
|
||||||
|
|||||||
+26
-9
@@ -17,6 +17,7 @@ set -euo pipefail
|
|||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
REPO="tsl0922/ttyd"
|
REPO="tsl0922/ttyd"
|
||||||
API_URL="https://api.github.com/repos/${REPO}/releases/latest"
|
API_URL="https://api.github.com/repos/${REPO}/releases/latest"
|
||||||
|
FALLBACK_TAG="1.7.7"
|
||||||
INSTALL_DIR="${HOME}/.local/bin"
|
INSTALL_DIR="${HOME}/.local/bin"
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -53,20 +54,24 @@ for cmd in curl uname; do
|
|||||||
command -v "$cmd" &>/dev/null || error "'$cmd' 명령어가 필요합니다."
|
command -v "$cmd" &>/dev/null || error "'$cmd' 명령어가 필요합니다."
|
||||||
done
|
done
|
||||||
|
|
||||||
# Fallback: jq가 없을 경우 python3를 사용해 JSON 정보 분석
|
# Fallback: jq가 없을 경우 python3 또는 grep을 사용해 JSON 정보 분석
|
||||||
if command -v jq &>/dev/null; then
|
if command -v jq &>/dev/null; then
|
||||||
_json_latest_tag() {
|
_json_latest_tag() {
|
||||||
jq -r '.tag_name'
|
jq -r 'select((.assets | length) > 0) | .tag_name'
|
||||||
}
|
}
|
||||||
else
|
elif command -v python3 &>/dev/null; then
|
||||||
command -v python3 &>/dev/null || error "'jq' 또는 'python3' 명령어가 설치되어 있어야 합니다."
|
|
||||||
_json_latest_tag() {
|
_json_latest_tag() {
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import sys, json
|
import sys, json
|
||||||
data = json.load(sys.stdin)
|
data = json.load(sys.stdin)
|
||||||
|
if data.get('assets'):
|
||||||
print(data.get('tag_name', ''))
|
print(data.get('tag_name', ''))
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
_json_latest_tag() {
|
||||||
|
grep -oE '"tag_name":[[:space:]]*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)"$/\1/'
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ────────────────────────────────────────────
|
# ────────────────────────────────────────────
|
||||||
@@ -121,12 +126,15 @@ detect_platform() {
|
|||||||
get_latest_release_tag() {
|
get_latest_release_tag() {
|
||||||
info "GitHub API를 통해 ttyd 최신 릴리스 버전을 가져오는 중..."
|
info "GitHub API를 통해 ttyd 최신 릴리스 버전을 가져오는 중..."
|
||||||
|
|
||||||
local release_json tag
|
local release_json="" tag=""
|
||||||
release_json="$(curl -fsSL "${API_URL}")" || error "GitHub API 호출에 실패했습니다."
|
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
|
if [[ -z "$tag" || "$tag" == "null" ]]; then
|
||||||
error "최신 릴리스 태그를 확인하는 데 실패했습니다."
|
warn "최신 릴리스 태그 조회 실패. 검증된 폴백 버전(${FALLBACK_TAG})을 사용합니다."
|
||||||
|
tag="${FALLBACK_TAG}"
|
||||||
fi
|
fi
|
||||||
echo "$tag"
|
echo "$tag"
|
||||||
}
|
}
|
||||||
@@ -156,11 +164,12 @@ main() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# 2) Linux / Windows Bash (바이너리 직접 설치 방식)
|
# 2) Linux / Windows Bash (바이너리 직접 설치 방식)
|
||||||
local tag download_url
|
local tag download_url fallback_url
|
||||||
tag="$(get_latest_release_tag)"
|
tag="$(get_latest_release_tag)"
|
||||||
info "최신 버전 감지: $tag"
|
info "최신 버전 감지: $tag"
|
||||||
|
|
||||||
download_url="https://github.com/tsl0922/ttyd/releases/download/${tag}/${asset_name}"
|
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"
|
mkdir -p "$INSTALL_DIR"
|
||||||
@@ -176,9 +185,17 @@ main() {
|
|||||||
|
|
||||||
info "바이너리 다운로드 중: $download_url"
|
info "바이너리 다운로드 중: $download_url"
|
||||||
if ! curl -fsSL "$download_url" -o "$tmp_file"; then
|
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"
|
rm -rf "$tmp_dir"
|
||||||
error "바이너리 다운로드에 실패했습니다. URL: $download_url"
|
error "바이너리 다운로드에 실패했습니다. URL: $download_url"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
info "설치 경로로 복사 중: $dest_file"
|
info "설치 경로로 복사 중: $dest_file"
|
||||||
mv "$tmp_file" "$dest_file"
|
mv "$tmp_file" "$dest_file"
|
||||||
|
|||||||
Reference in new issue
Block a user