feat: updated coyote installation scripts to detect when gnu is installable
This commit is contained in:
+87
-43
@@ -67,7 +67,13 @@ if ($os -eq 'windows') {
|
|||||||
try { getconf GNU_LIBC_VERSION *> $null; if ($LASTEXITCODE -eq 0) { $libc = 'gnu' } } catch { }
|
try { getconf GNU_LIBC_VERSION *> $null; if ($LASTEXITCODE -eq 0) { $libc = 'gnu' } } catch { }
|
||||||
try { if ((ldd --version 2>&1 | Out-String) -imatch 'glibc') { $libc = 'gnu' } } catch { }
|
try { if ((ldd --version 2>&1 | Out-String) -imatch 'glibc') { $libc = 'gnu' } } catch { }
|
||||||
if ($libc -eq 'gnu') {
|
if ($libc -eq 'gnu') {
|
||||||
$candidates += 'coyote-x86_64-unknown-linux-gnu.tar.gz'
|
$libssl3 = $false
|
||||||
|
try { if ((ldconfig -p 2>&1 | Out-String) -match 'libssl\.so\.3') { $libssl3 = $true } } catch { }
|
||||||
|
if ($libssl3) {
|
||||||
|
$candidates += 'coyote-x86_64-unknown-linux-gnu.tar.gz'
|
||||||
|
} else {
|
||||||
|
Write-Info "glibc detected but OpenSSL 3 (libssl.so.3) not found; using musl build"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$candidates += 'coyote-x86_64-unknown-linux-musl.tar.gz'
|
$candidates += 'coyote-x86_64-unknown-linux-musl.tar.gz'
|
||||||
} else {
|
} else {
|
||||||
@@ -77,54 +83,92 @@ if ($os -eq 'windows') {
|
|||||||
Fail "Unsupported OS for this installer: $os"
|
Fail "Unsupported OS for this installer: $os"
|
||||||
}
|
}
|
||||||
|
|
||||||
$asset = $null
|
$tmp = New-Item -ItemType Directory -Force -Path ([IO.Path]::Combine([IO.Path]::GetTempPath(), "coyote-$(Get-Random)"))
|
||||||
|
|
||||||
|
$exec = if ($isWin) { 'coyote.exe' } else { 'coyote' }
|
||||||
|
$dest = Join-Path $BinDir $exec
|
||||||
|
|
||||||
|
$installed = $false
|
||||||
|
$tried = @()
|
||||||
|
$attempt = 0
|
||||||
foreach ($c in $candidates) {
|
foreach ($c in $candidates) {
|
||||||
$asset = $release.assets | Where-Object { $_.name -eq $c } | Select-Object -First 1
|
$asset = $release.assets | Where-Object { $_.name -eq $c } | Select-Object -First 1
|
||||||
if ($asset) { break }
|
if (-not $asset) {
|
||||||
|
$tried += "${c}: no matching release asset"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$attempt++
|
||||||
|
$work = New-Item -ItemType Directory -Force -Path (Join-Path $tmp.FullName "attempt-$attempt")
|
||||||
|
|
||||||
|
Write-Info "Selected asset: $($asset.name)"
|
||||||
|
Write-Info "Download URL: $($asset.browser_download_url)"
|
||||||
|
|
||||||
|
$archive = Join-Path $work.FullName 'asset'
|
||||||
|
try {
|
||||||
|
Invoke-WebRequest -UseBasicParsing -Headers @{ 'User-Agent' = 'coyote-installer' } -Uri $asset.browser_download_url -OutFile $archive
|
||||||
|
} catch {
|
||||||
|
Write-Info "Failed to download ${c}; trying next candidate. $_"
|
||||||
|
$tried += "${c}: download failed"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$extractDir = Join-Path $work.FullName 'extract'; New-Item -ItemType Directory -Force -Path $extractDir | Out-Null
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($asset.name -match '\.zip$') {
|
||||||
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||||
|
[System.IO.Compression.ZipFile]::ExtractToDirectory($archive, $extractDir)
|
||||||
|
} elseif ($asset.name -match '\.tar\.gz$' -or $asset.name -match '\.tgz$') {
|
||||||
|
$tar = Get-Command tar -ErrorAction SilentlyContinue
|
||||||
|
if ($tar) { & $tar.Source -xzf $archive -C $extractDir }
|
||||||
|
else { throw "Asset is tar archive but 'tar' is not available." }
|
||||||
|
} else {
|
||||||
|
try { Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::ExtractToDirectory($archive, $extractDir) }
|
||||||
|
catch {
|
||||||
|
$tar = Get-Command tar -ErrorAction SilentlyContinue
|
||||||
|
if ($tar) { & $tar.Source -xf $archive -C $extractDir } else { throw "Unknown archive format; neither zip nor tar workable." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Info "Failed to extract ${c}; trying next candidate. $_"
|
||||||
|
$tried += "${c}: extract failed"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$bin = $null
|
||||||
|
Get-ChildItem -Recurse -File $extractDir | ForEach-Object {
|
||||||
|
if ($isWin) { if ($_.Name -ieq 'coyote.exe') { $bin = $_.FullName } }
|
||||||
|
else { if ($_.Name -ieq 'coyote') { $bin = $_.FullName } }
|
||||||
|
}
|
||||||
|
if (-not $bin) {
|
||||||
|
Write-Info "Could not find coyote binary inside ${c}; trying next candidate"
|
||||||
|
$tried += "${c}: no coyote binary in archive"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $isWin) { try { & chmod +x -- $bin } catch {} }
|
||||||
|
|
||||||
|
$works = $false
|
||||||
|
try { & $bin --version *> $null; if ($LASTEXITCODE -eq 0) { $works = $true } } catch { }
|
||||||
|
if (-not $works) {
|
||||||
|
Write-Info "Downloaded $c but it failed to run on this system; trying next candidate"
|
||||||
|
$tried += "${c}: binary failed to run on this system"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
Copy-Item -Force $bin $dest
|
||||||
|
Write-Info "Installed: $dest"
|
||||||
|
$installed = $true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if (-not $asset) {
|
|
||||||
Write-Error "No matching asset found for $os-$arch. Tried:"; $candidates | ForEach-Object { Write-Error " - $_" }
|
if (-not $installed) {
|
||||||
|
Write-Error "No usable asset found for $os-$arch. Tried:"
|
||||||
|
$tried | ForEach-Object { Write-Error " - $_" }
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Info "Selected asset: $($asset.name)"
|
|
||||||
Write-Info "Download URL: $($asset.browser_download_url)"
|
|
||||||
|
|
||||||
$tmp = New-Item -ItemType Directory -Force -Path ([IO.Path]::Combine([IO.Path]::GetTempPath(), "coyote-$(Get-Random)"))
|
|
||||||
$archive = Join-Path $tmp.FullName 'asset'
|
|
||||||
try { Invoke-WebRequest -UseBasicParsing -Headers @{ 'User-Agent' = 'coyote-installer' } -Uri $asset.browser_download_url -OutFile $archive } catch { Fail "Failed to download asset. $_" }
|
|
||||||
|
|
||||||
$extractDir = Join-Path $tmp.FullName 'extract'; New-Item -ItemType Directory -Force -Path $extractDir | Out-Null
|
|
||||||
|
|
||||||
if ($asset.name -match '\.zip$') {
|
|
||||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
||||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($archive, $extractDir)
|
|
||||||
} elseif ($asset.name -match '\.tar\.gz$' -or $asset.name -match '\.tgz$') {
|
|
||||||
$tar = Get-Command tar -ErrorAction SilentlyContinue
|
|
||||||
if ($tar) { & $tar.Source -xzf $archive -C $extractDir }
|
|
||||||
else { Fail "Asset is tar archive but 'tar' is not available." }
|
|
||||||
} else {
|
|
||||||
try { Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::ExtractToDirectory($archive, $extractDir) }
|
|
||||||
catch {
|
|
||||||
$tar = Get-Command tar -ErrorAction SilentlyContinue
|
|
||||||
if ($tar) { & $tar.Source -xf $archive -C $extractDir } else { Fail "Unknown archive format; neither zip nor tar workable." }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$bin = $null
|
|
||||||
Get-ChildItem -Recurse -File $extractDir | ForEach-Object {
|
|
||||||
if ($isWin) { if ($_.Name -ieq 'coyote.exe') { $bin = $_.FullName } }
|
|
||||||
else { if ($_.Name -ieq 'coyote') { $bin = $_.FullName } }
|
|
||||||
}
|
|
||||||
if (-not $bin) { Fail "Could not find coyote binary inside the archive." }
|
|
||||||
|
|
||||||
if (-not $isWin) { try { & chmod +x -- $bin } catch {} }
|
|
||||||
|
|
||||||
$exec = if ($isWin) { 'coyote.exe'} else { 'coyote' }
|
|
||||||
$dest = Join-Path $BinDir $exec
|
|
||||||
Copy-Item -Force $bin $dest
|
|
||||||
Write-Info "Installed: $dest"
|
|
||||||
|
|
||||||
if ($isWin) {
|
if ($isWin) {
|
||||||
$pathParts = ($env:Path -split ';') | Where-Object { $_ -ne '' }
|
$pathParts = ($env:Path -split ';') | Where-Object { $_ -ne '' }
|
||||||
if ($pathParts -notcontains $BinDir) {
|
if ($pathParts -notcontains $BinDir) {
|
||||||
|
|||||||
+87
-48
@@ -122,7 +122,11 @@ elif [[ "$OS" == "linux" ]]; then
|
|||||||
if ldd --version 2>&1 | grep -qi glibc; then LIBC="gnu"; fi
|
if ldd --version 2>&1 | grep -qi glibc; then LIBC="gnu"; fi
|
||||||
|
|
||||||
if [[ "$LIBC" == "gnu" ]]; then
|
if [[ "$LIBC" == "gnu" ]]; then
|
||||||
ASSET_CANDIDATES+=("coyote-x86_64-unknown-linux-gnu.tar.gz")
|
if ldconfig -p 2>/dev/null | grep -q 'libssl\.so\.3'; then
|
||||||
|
ASSET_CANDIDATES+=("coyote-x86_64-unknown-linux-gnu.tar.gz")
|
||||||
|
else
|
||||||
|
log "glibc detected but OpenSSL 3 (libssl.so.3) not found; using musl build"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ASSET_CANDIDATES+=("coyote-x86_64-unknown-linux-musl.tar.gz")
|
ASSET_CANDIDATES+=("coyote-x86_64-unknown-linux-musl.tar.gz")
|
||||||
@@ -137,66 +141,101 @@ DL_URLS=$(grep -oE '"browser_download_url":[[:space:]]*"[^"]+"' "$JSON" \
|
|||||||
| sed -E 's/.*"browser_download_url":[[:space:]]*"//; s/"$//' \
|
| sed -E 's/.*"browser_download_url":[[:space:]]*"//; s/"$//' \
|
||||||
|| true)
|
|| true)
|
||||||
|
|
||||||
ASSET_NAME=""; ASSET_URL=""
|
INSTALLED=""
|
||||||
|
TRIED=()
|
||||||
|
ATTEMPT=0
|
||||||
for candidate in "${ASSET_CANDIDATES[@]}"; do
|
for candidate in "${ASSET_CANDIDATES[@]}"; do
|
||||||
|
ASSET_URL=""
|
||||||
while IFS= read -r url; do
|
while IFS= read -r url; do
|
||||||
[[ -z "$url" ]] && continue
|
[[ -z "$url" ]] && continue
|
||||||
if [[ "$url" == */"$candidate" ]]; then
|
if [[ "$url" == */"$candidate" ]]; then
|
||||||
ASSET_NAME="$candidate"
|
|
||||||
ASSET_URL="$url"
|
ASSET_URL="$url"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done <<< "$DL_URLS"
|
done <<< "$DL_URLS"
|
||||||
[[ -n "$ASSET_URL" ]] && break
|
|
||||||
|
if [[ -z "$ASSET_URL" ]]; then
|
||||||
|
TRIED+=("$candidate: no matching release asset")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
ATTEMPT=$((ATTEMPT + 1))
|
||||||
|
WORK="$TMPDIR/attempt-$ATTEMPT"
|
||||||
|
mkdir -p "$WORK"
|
||||||
|
|
||||||
|
log "Selected asset: $candidate"
|
||||||
|
log "Download URL: $ASSET_URL"
|
||||||
|
|
||||||
|
ARCHIVE="$WORK/asset"
|
||||||
|
if [[ "$DL" == "curl" ]]; then
|
||||||
|
if ! curl -fL -H 'User-Agent: coyote-installer' "$ASSET_URL" -o "$ARCHIVE"; then
|
||||||
|
log "Failed to download $candidate; trying next candidate"
|
||||||
|
TRIED+=("$candidate: download failed")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if ! wget -q --header='User-Agent: coyote-installer' "$ASSET_URL" -O "$ARCHIVE"; then
|
||||||
|
log "Failed to download $candidate; trying next candidate"
|
||||||
|
TRIED+=("$candidate: download failed")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
EXTRACTED_DIR="$WORK/extracted"; mkdir -p "$EXTRACTED_DIR"
|
||||||
|
|
||||||
|
if tar -tf "$ARCHIVE" >/dev/null 2>&1; then
|
||||||
|
if ! tar -xzf "$ARCHIVE" -C "$EXTRACTED_DIR"; then
|
||||||
|
log "Failed to extract $candidate; trying next candidate"
|
||||||
|
TRIED+=("$candidate: extract failed")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if command -v unzip >/dev/null 2>&1; then
|
||||||
|
if ! unzip -q "$ARCHIVE" -d "$EXTRACTED_DIR"; then
|
||||||
|
log "Failed to extract $candidate; trying next candidate"
|
||||||
|
TRIED+=("$candidate: extract failed")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "Unknown archive format for $candidate and 'unzip' is not available; trying next candidate"
|
||||||
|
TRIED+=("$candidate: unknown archive format and 'unzip' unavailable")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
BIN_PATH=""
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
base=$(basename "$f")
|
||||||
|
if [[ "$base" == "coyote" ]]; then
|
||||||
|
BIN_PATH="$f"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done < <(find "$EXTRACTED_DIR" -type f -print0)
|
||||||
|
|
||||||
|
if [[ -z "$BIN_PATH" ]]; then
|
||||||
|
log "Could not find 'coyote' binary in $candidate; trying next candidate"
|
||||||
|
TRIED+=("$candidate: no 'coyote' binary in archive")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x "$BIN_PATH"
|
||||||
|
if ! "$BIN_PATH" --version >/dev/null 2>&1; then
|
||||||
|
log "Downloaded $candidate but it failed to run on this system; trying next candidate"
|
||||||
|
TRIED+=("$candidate: binary failed to run on this system")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -m 0755 "$BIN_PATH" "${BIN_DIR}/coyote"
|
||||||
|
INSTALLED="$candidate"
|
||||||
|
break
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -z "$ASSET_URL" ]]; then
|
if [[ -z "$INSTALLED" ]]; then
|
||||||
echo "Error: no matching asset found for ${OS}-${ARCH}. Tried:" >&2
|
echo "Error: no usable asset found for ${OS}-${ARCH}. Tried:" >&2
|
||||||
for c in "${ASSET_CANDIDATES[@]}"; do echo " - $c" >&2; done
|
for t in "${TRIED[@]}"; do echo " - $t" >&2; done
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log "Selected asset: $ASSET_NAME"
|
|
||||||
log "Download URL: $ASSET_URL"
|
|
||||||
|
|
||||||
ARCHIVE="$TMPDIR/asset"
|
|
||||||
if [[ "$DL" == "curl" ]]; then
|
|
||||||
curl -fL -H 'User-Agent: coyote-installer' "$ASSET_URL" -o "$ARCHIVE"
|
|
||||||
else
|
|
||||||
wget -q --header='User-Agent: coyote-installer' "$ASSET_URL" -O "$ARCHIVE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
WORK="$TMPDIR/work"; mkdir -p "$WORK"
|
|
||||||
EXTRACTED_DIR="$WORK/extracted"; mkdir -p "$EXTRACTED_DIR"
|
|
||||||
|
|
||||||
if tar -tf "$ARCHIVE" >/dev/null 2>&1; then
|
|
||||||
tar -xzf "$ARCHIVE" -C "$EXTRACTED_DIR"
|
|
||||||
else
|
|
||||||
if command -v unzip >/dev/null 2>&1; then
|
|
||||||
unzip -q "$ARCHIVE" -d "$EXTRACTED_DIR"
|
|
||||||
else
|
|
||||||
echo "Error: unknown archive format; install 'unzip'" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
BIN_PATH=""
|
|
||||||
while IFS= read -r -d '' f; do
|
|
||||||
base=$(basename "$f")
|
|
||||||
if [[ "$base" == "coyote" ]]; then
|
|
||||||
BIN_PATH="$f"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done < <(find "$EXTRACTED_DIR" -type f -print0)
|
|
||||||
|
|
||||||
if [[ -z "$BIN_PATH" ]]; then
|
|
||||||
echo "Error: could not find 'coyote' binary in the archive" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
chmod +x "$BIN_PATH"
|
|
||||||
install -m 0755 "$BIN_PATH" "${BIN_DIR}/coyote"
|
|
||||||
|
|
||||||
log "Installed: ${BIN_DIR}/coyote"
|
log "Installed: ${BIN_DIR}/coyote"
|
||||||
|
|
||||||
case ":$PATH:" in
|
case ":$PATH:" in
|
||||||
|
|||||||
+1
-22
@@ -68,30 +68,9 @@ fn normalize_version(requested: Option<String>) -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn host_has_glibc() -> bool {
|
|
||||||
if process::Command::new("getconf")
|
|
||||||
.arg("GNU_LIBC_VERSION")
|
|
||||||
.output()
|
|
||||||
.is_ok_and(|out| out.status.success())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
process::Command::new("ldd")
|
|
||||||
.arg("--version")
|
|
||||||
.output()
|
|
||||||
.is_ok_and(|out| {
|
|
||||||
let combined = format!(
|
|
||||||
"{}{}",
|
|
||||||
String::from_utf8_lossy(&out.stdout),
|
|
||||||
String::from_utf8_lossy(&out.stderr)
|
|
||||||
);
|
|
||||||
combined.to_lowercase().contains("glibc")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn preferred_update_target() -> Option<&'static str> {
|
fn preferred_update_target() -> Option<&'static str> {
|
||||||
match (env::consts::OS, env::consts::ARCH) {
|
match (env::consts::OS, env::consts::ARCH) {
|
||||||
("linux", "x86_64") if host_has_glibc() => Some("x86_64-unknown-linux-gnu"),
|
("linux", "x86_64") if cfg!(target_env = "gnu") => Some("x86_64-unknown-linux-gnu"),
|
||||||
("linux", "x86_64") => Some("x86_64-unknown-linux-musl"),
|
("linux", "x86_64") => Some("x86_64-unknown-linux-musl"),
|
||||||
// No aarch64 gnu asset is published; musl is the only option.
|
// No aarch64 gnu asset is published; musl is the only option.
|
||||||
("linux", "aarch64") => Some("aarch64-unknown-linux-musl"),
|
("linux", "aarch64") => Some("aarch64-unknown-linux-musl"),
|
||||||
|
|||||||
Reference in New Issue
Block a user