refactor(kernel): report kernel download progress through the sink
get_default_kernel emits Progress events for the APK transfer instead of drawing a bar to stderr from inside the library.
This commit is contained in:
@@ -63,7 +63,7 @@ fn main() -> Result<()> {
|
||||
}
|
||||
None => {
|
||||
veprintln!("QEMU mode: downloading default kernel...");
|
||||
kernel::get_default_kernel(cache.dir(), &arch)?
|
||||
kernel::get_default_kernel(cache.dir(), &arch, &ecr::NoProgress)?
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+23
-18
@@ -17,9 +17,9 @@
|
||||
//! kernel image gzipped, and QEMU's riscv `-kernel` loader understands
|
||||
//! only ELF, uImage and raw images.
|
||||
|
||||
use crate::progress::{Progress, Unit};
|
||||
use crate::veprintln;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use std::io::{Read, Seek};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
@@ -237,7 +237,12 @@ fn find_kernel_package(branch: &str, arch: &str) -> Result<(&'static str, String
|
||||
}
|
||||
|
||||
/// Download and extract the kernel from an Alpine package repository
|
||||
fn download_alpine_kernel(branch: &str, arch: &str, dest: &Path) -> Result<()> {
|
||||
fn download_alpine_kernel(
|
||||
branch: &str,
|
||||
arch: &str,
|
||||
dest: &Path,
|
||||
progress: &dyn Progress,
|
||||
) -> Result<()> {
|
||||
let (package, version) = find_kernel_package(branch, arch)?;
|
||||
veprintln!("Found {} version: {}", package, version);
|
||||
|
||||
@@ -252,7 +257,7 @@ fn download_alpine_kernel(branch: &str, arch: &str, dest: &Path) -> Result<()> {
|
||||
|
||||
// Use async download via the existing download module pattern
|
||||
let rt = tokio::runtime::Runtime::new().context("Failed to create Tokio runtime")?;
|
||||
rt.block_on(download_kernel_async(&url, dest))?;
|
||||
rt.block_on(download_kernel_async(&url, dest, progress))?;
|
||||
|
||||
// Extract the kernel image from the APK, then store it decompressed.
|
||||
// Remove the ~45MB APK whatever the outcome — don't leave it behind
|
||||
@@ -264,7 +269,7 @@ fn download_alpine_kernel(branch: &str, arch: &str, dest: &Path) -> Result<()> {
|
||||
result
|
||||
}
|
||||
|
||||
async fn download_kernel_async(url: &str, dest: &Path) -> Result<()> {
|
||||
async fn download_kernel_async(url: &str, dest: &Path, progress: &dyn Progress) -> Result<()> {
|
||||
use futures_util::StreamExt;
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(300))
|
||||
@@ -286,13 +291,10 @@ async fn download_kernel_async(url: &str, dest: &Path) -> Result<()> {
|
||||
|
||||
let total_size = response.content_length().unwrap_or(0);
|
||||
|
||||
// Setup progress bar
|
||||
let pb = ProgressBar::new(total_size);
|
||||
pb.set_style(
|
||||
ProgressStyle::default_bar()
|
||||
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
|
||||
.unwrap()
|
||||
.progress_chars("#>-"),
|
||||
progress.begin(
|
||||
"Downloading kernel",
|
||||
Unit::Bytes,
|
||||
(total_size > 0).then_some(total_size),
|
||||
);
|
||||
|
||||
let temp_apk = dest.with_extension("apk.partial");
|
||||
@@ -300,7 +302,6 @@ async fn download_kernel_async(url: &str, dest: &Path) -> Result<()> {
|
||||
.await
|
||||
.context("Failed to create temp APK file")?;
|
||||
|
||||
let mut downloaded: u64 = 0;
|
||||
let mut stream = response.bytes_stream();
|
||||
|
||||
while let Some(chunk) = stream.next().await {
|
||||
@@ -308,15 +309,14 @@ async fn download_kernel_async(url: &str, dest: &Path) -> Result<()> {
|
||||
tokio::io::AsyncWriteExt::write_all(&mut file, &chunk)
|
||||
.await
|
||||
.context("Failed to write chunk")?;
|
||||
downloaded += chunk.len() as u64;
|
||||
pb.set_position(downloaded);
|
||||
progress.advance(chunk.len() as u64);
|
||||
}
|
||||
|
||||
tokio::io::AsyncWriteExt::flush(&mut file)
|
||||
.await
|
||||
.context("Failed to flush file")?;
|
||||
|
||||
pb.finish_with_message("Download complete");
|
||||
progress.finish();
|
||||
|
||||
// Rename to final name
|
||||
let final_apk = dest.with_extension("apk");
|
||||
@@ -392,8 +392,13 @@ fn decompress_kernel_if_gzipped(path: &Path) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Get the path to the cached default kernel for the given architecture.
|
||||
/// Downloads and caches it if not present.
|
||||
pub fn get_default_kernel(cache_dir: &Path, arch: &str) -> Result<PathBuf> {
|
||||
/// Downloads and caches it if not present, reporting download progress
|
||||
/// through `progress`.
|
||||
pub fn get_default_kernel(
|
||||
cache_dir: &Path,
|
||||
arch: &str,
|
||||
progress: &dyn Progress,
|
||||
) -> Result<PathBuf> {
|
||||
let alpine_arch = alpine_kernel_arch(arch);
|
||||
|
||||
// Cache filename includes architecture
|
||||
@@ -414,7 +419,7 @@ pub fn get_default_kernel(cache_dir: &Path, arch: &str) -> Result<PathBuf> {
|
||||
veprintln!("Using Alpine branch: {}", branch);
|
||||
|
||||
// Download and extract the kernel
|
||||
download_alpine_kernel(&branch, alpine_arch, &kernel_path)?;
|
||||
download_alpine_kernel(&branch, alpine_arch, &kernel_path, progress)?;
|
||||
|
||||
Ok(kernel_path)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user