From 0cabbb84a8679a0987251202d5d9840828edce85 Mon Sep 17 00:00:00 2001 From: Michal R Date: Thu, 23 Oct 2025 15:46:05 +0200 Subject: [PATCH] xtask: Allow to run VM integration tests without dpkg Debian packages are just nested archives, where the outer one is ar and the inner one is lzma2 tarball. Use Rust crates to unpack them. --- Cargo.toml | 1 + xtask/Cargo.toml | 2 ++ xtask/src/run.rs | 52 ++++++++++++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 81409567..048494b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ rust-version = "1.85.0" # them to do that, but in the meantime we need to be careful. [workspace.dependencies] anyhow = { version = "1", default-features = false } +ar = { version = "0.9", default-features = false } assert_matches = { version = "1.5.0", default-features = false } base64 = { version = "0.22.1", default-features = false } bindgen = { version = "0.72", default-features = false } diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 04df81f6..d615859f 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -15,6 +15,7 @@ workspace = true [dependencies] anyhow = { workspace = true, features = ["std"] } +ar = { workspace = true } aya-tool = { path = "../aya-tool", version = "0.1.0", default-features = false } cargo_metadata = { workspace = true } clap = { workspace = true, features = ["derive"] } @@ -30,3 +31,4 @@ syn = { workspace = true } tar = { workspace = true } tempfile = { workspace = true } walkdir = { workspace = true } +xz2 = { workspace = true } diff --git a/xtask/src/run.rs b/xtask/src/run.rs index b52e8890..fba369c6 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -1,8 +1,8 @@ use std::{ ffi::{OsStr, OsString}, fmt::Write as _, - fs::{self, OpenOptions}, - io::{BufRead as _, BufReader, Write as _}, + fs::{self, File, OpenOptions}, + io::{BufRead as _, BufReader, Cursor, Read as _, Write as _}, ops::Deref as _, path::{self, Path, PathBuf}, process::{Child, ChildStdin, Command, Output, Stdio}, @@ -300,29 +300,43 @@ pub(crate) fn run(opts: Options) -> Result<()> { fs::create_dir_all(&archive_dir) .with_context(|| format!("failed to create {}", archive_dir.display()))?; - let mut dpkg = Command::new("dpkg-deb"); - dpkg.arg("--fsys-tarfile") - .arg(archive) - .stdout(Stdio::piped()); - let mut dpkg_child = dpkg - .spawn() - .with_context(|| format!("failed to spawn {dpkg:?}"))?; - let Child { stdout, .. } = &mut dpkg_child; - let stdout = stdout.take().unwrap(); - let mut archive_reader = tar::Archive::new(stdout); - archive_reader.unpack(&archive_dir).with_context(|| { + let archive_reader = File::open(archive).with_context(|| { + format!("failed to open the deb package {}", archive.display()) + })?; + let mut archive_reader = ar::Archive::new(archive_reader); + // This would've been easier if `ar` crate was providing some iterator + // over entries... + // https://github.com/mdsteele/rust-ar/issues/15 + let mut inner_archive = None; + while let Some(entry) = archive_reader.next_entry() { + let mut entry = entry.with_context(|| { + format!( + "failed to read an entry of the deb package {}", + archive.display() + ) + })?; + if entry.header().identifier() == b"data.tar.xz" { + let mut buf = Vec::with_capacity(entry.header().size() as usize); + let _bytes_read = entry.read_to_end(&mut buf)?; + inner_archive = Some(buf); + break; + } + } + let Some(inner_archive) = inner_archive else { + bail!( + "cound not find the `data.tar.xz` archive inside the deb package {}", + archive.display() + ); + }; + let inner_archive_reader = xz2::read::XzDecoder::new(Cursor::new(inner_archive)); + let mut inner_archive_reader = tar::Archive::new(inner_archive_reader); + inner_archive_reader.unpack(&archive_dir).with_context(|| { format!( "failed to unpack archive {} to {}", archive.display(), archive_dir.display() ) })?; - let status = dpkg_child - .wait() - .with_context(|| format!("failed to wait for {dpkg:?}"))?; - if !status.success() { - bail!("{dpkg:?} exited with {status}"); - } let mut kernel_images = Vec::new(); let mut configs = Vec::new();