mirror of
https://codeberg.org/icewind/haze.git
synced 2026-06-04 01:24:09 +02:00
allow using release sources
This commit is contained in:
parent
8941c697fb
commit
f569ca17e2
9 changed files with 1226 additions and 113 deletions
124
src/sources.rs
124
src/sources.rs
|
|
@ -1,6 +1,17 @@
|
|||
use crate::config::HazeConfig;
|
||||
use camino::Utf8PathBuf;
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
use miette::{Context, IntoDiagnostic, Report, Result};
|
||||
use reqwest::header::HeaderName;
|
||||
use reqwest::{Client, IntoUrl, Response};
|
||||
use sha2::{Digest, Sha512};
|
||||
use std::fs::read_to_string;
|
||||
use std::io::Cursor;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
use tokio::fs::create_dir_all;
|
||||
use zip::read::root_dir_common_filter;
|
||||
use zip::ZipArchive;
|
||||
|
||||
pub struct Sources {
|
||||
#[allow(dead_code)]
|
||||
|
|
@ -49,3 +60,116 @@ impl Sources {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn download_nc(config: &HazeConfig, version: &str) -> Result<Utf8PathBuf> {
|
||||
if !version.chars().all(|c| c.is_ascii_digit() || c == '.') {
|
||||
return Err(Report::msg(format!("Invalid version: {version}")));
|
||||
}
|
||||
let root = config.work_dir.join("sources");
|
||||
create_dir_all(&root)
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err("failed to create parent directory for sources")?;
|
||||
let dest = root.join(version);
|
||||
if !dest.exists() {
|
||||
let progress = MultiProgress::new();
|
||||
let download_style = ProgressStyle::with_template("{spinner:.green} {msg} [{elapsed_precise}] [{bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
|
||||
.unwrap();
|
||||
let download_bar = ProgressBar::new(0)
|
||||
.with_message("Downloading")
|
||||
.with_style(download_style.clone());
|
||||
let download_bar = progress.add(download_bar);
|
||||
|
||||
let archive = download_url(
|
||||
format!("https://download.nextcloud.com/server/releases/nextcloud-{version}.zip"),
|
||||
|size| {
|
||||
download_bar.set_length(size);
|
||||
},
|
||||
|count| {
|
||||
download_bar.inc(count);
|
||||
},
|
||||
)
|
||||
.await
|
||||
.wrap_err_with(|| format!("Failed to download archive for {}", version))?;
|
||||
download_bar.finish();
|
||||
|
||||
let expected_hash = download_text(format!(
|
||||
"https://download.nextcloud.com/server/releases/nextcloud-{version}.zip.sha512"
|
||||
))
|
||||
.await
|
||||
.wrap_err_with(|| format!("Failed to download hash for {}", version))?;
|
||||
let expected_hash = expected_hash
|
||||
.split_once(' ')
|
||||
.map(|(hash, _)| hash)
|
||||
.unwrap_or(expected_hash.trim());
|
||||
|
||||
let hash_bar = ProgressBar::new(download_bar.length().unwrap_or_default())
|
||||
.with_message("Validating")
|
||||
.with_style(download_style.clone());
|
||||
let hash_bar = progress.add(hash_bar);
|
||||
let mut hasher = Sha512::new();
|
||||
for chunk in archive.chunks(1014 * 1024) {
|
||||
hash_bar.inc(chunk.len() as u64);
|
||||
hasher.update(chunk);
|
||||
}
|
||||
let hash = hasher.finalize();
|
||||
|
||||
let hash = base16ct::lower::encode_string(&hash);
|
||||
if expected_hash != hash {
|
||||
return Err(Report::msg(format!(
|
||||
"Invalid hash for downloaded: {version}, expected {expected_hash} but got {hash}"
|
||||
)));
|
||||
}
|
||||
hash_bar.finish();
|
||||
|
||||
let extract_bar = ProgressBar::new_spinner().with_message("Extracing");
|
||||
extract_bar.enable_steady_tick(Duration::from_millis(100));
|
||||
let extract_bar = progress.add(extract_bar);
|
||||
let mut archive = ZipArchive::new(Cursor::new(archive)).into_diagnostic()?;
|
||||
archive
|
||||
.extract_unwrapped_root_dir(&dest, root_dir_common_filter)
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to extract archive")?;
|
||||
extract_bar.finish();
|
||||
}
|
||||
Ok(dest)
|
||||
}
|
||||
|
||||
async fn download_url<U: IntoUrl, SizeFN: FnOnce(u64), ProgressFN: Fn(u64)>(
|
||||
url: U,
|
||||
size: SizeFN,
|
||||
progress: ProgressFN,
|
||||
) -> Result<Vec<u8>> {
|
||||
let mut res = get_url(url).await?.error_for_status().into_diagnostic()?;
|
||||
let mut buff = Vec::new();
|
||||
|
||||
size(res.content_length().unwrap_or_default());
|
||||
while let Some(chunk) = res.chunk().await.into_diagnostic()? {
|
||||
progress(chunk.len() as u64);
|
||||
buff.extend(chunk);
|
||||
}
|
||||
Ok(buff)
|
||||
}
|
||||
async fn download_text<U: IntoUrl>(url: U) -> Result<String> {
|
||||
get_url(url)
|
||||
.await?
|
||||
.error_for_status()
|
||||
.into_diagnostic()?
|
||||
.text()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
}
|
||||
|
||||
async fn get_url<U: IntoUrl>(url: U) -> Result<Response> {
|
||||
Client::builder()
|
||||
.build()
|
||||
.into_diagnostic()?
|
||||
.get(url)
|
||||
.header(
|
||||
HeaderName::from_static("user-agent"),
|
||||
format!("haze {}", env!("CARGO_PKG_VERSION")),
|
||||
)
|
||||
.send()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue