pkgwatch/src/fetcher.rs

49 lines
1.3 KiB
Rust
Raw Normal View History

use anyhow::{Context, Result};
use serde::Deserialize;
use std::path::{Path, PathBuf};
#[derive(Debug, Deserialize)]
struct Release {
assets: Vec<Asset>,
}
#[derive(Debug, Deserialize)]
struct Asset {
name: String,
browser_download_url: String,
}
/// Downloads the release asset named exactly `asset_name` for `repo`@`tag`
/// into `dest_dir`, returning the local path.
pub fn download_asset(
client: &reqwest::blocking::Client,
repo: &str,
tag: &str,
asset_name: &str,
dest_dir: &Path,
) -> Result<PathBuf> {
let api_url = format!("https://api.github.com/repos/{repo}/releases/tags/{tag}");
let release: Release = client
.get(&api_url)
.send()?
.error_for_status()
.with_context(|| format!("fetching release metadata from {api_url}"))?
.json()?;
let asset = release
.assets
.iter()
.find(|a| a.name == asset_name)
.with_context(|| format!("no asset named '{asset_name}' in {repo}@{tag}"))?;
std::fs::create_dir_all(dest_dir)?;
let dest_path = dest_dir.join(&asset.name);
let bytes = client
.get(&asset.browser_download_url)
.send()?
.error_for_status()?
.bytes()?;
std::fs::write(&dest_path, &bytes)?;
Ok(dest_path)
}