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.
reviewable/pr1373/r1
Michal R 2 weeks ago
parent 03e8487177
commit 5fdae57dfe

@ -62,6 +62,7 @@ rust-version = "1.85.0"
# them to do that, but in the meantime we need to be careful. # them to do that, but in the meantime we need to be careful.
[workspace.dependencies] [workspace.dependencies]
anyhow = { version = "1", default-features = false } anyhow = { version = "1", default-features = false }
ar = { version = "0.9", default-features = false }
assert_matches = { version = "1.5.0", default-features = false } assert_matches = { version = "1.5.0", default-features = false }
base64 = { version = "0.22.1", default-features = false } base64 = { version = "0.22.1", default-features = false }
bindgen = { version = "0.72", default-features = false } bindgen = { version = "0.72", default-features = false }

@ -15,6 +15,7 @@ workspace = true
[dependencies] [dependencies]
anyhow = { workspace = true, features = ["std"] } anyhow = { workspace = true, features = ["std"] }
ar = { workspace = true }
aya-tool = { path = "../aya-tool", version = "0.1.0", default-features = false } aya-tool = { path = "../aya-tool", version = "0.1.0", default-features = false }
cargo_metadata = { workspace = true } cargo_metadata = { workspace = true }
clap = { workspace = true, features = ["derive"] } clap = { workspace = true, features = ["derive"] }
@ -30,3 +31,4 @@ syn = { workspace = true }
tar = { workspace = true } tar = { workspace = true }
tempfile = { workspace = true } tempfile = { workspace = true }
walkdir = { workspace = true } walkdir = { workspace = true }
xz2 = { workspace = true }

@ -1,8 +1,8 @@
use std::{ use std::{
ffi::{OsStr, OsString}, ffi::{OsStr, OsString},
fmt::Write as _, fmt::Write as _,
fs::{self, OpenOptions}, fs::{self, File, OpenOptions},
io::{BufRead as _, BufReader, Write as _}, io::{BufRead as _, BufReader, Cursor, Read, Write as _},
ops::Deref as _, ops::Deref as _,
path::{self, Path, PathBuf}, path::{self, Path, PathBuf},
process::{Child, ChildStdin, Command, Output, Stdio}, process::{Child, ChildStdin, Command, Output, Stdio},
@ -300,29 +300,42 @@ pub(crate) fn run(opts: Options) -> Result<()> {
fs::create_dir_all(&archive_dir) fs::create_dir_all(&archive_dir)
.with_context(|| format!("failed to create {}", archive_dir.display()))?; .with_context(|| format!("failed to create {}", archive_dir.display()))?;
let mut dpkg = Command::new("dpkg-deb"); let archive_reader = File::open(archive).with_context(|| {
dpkg.arg("--fsys-tarfile") format!("failed to open the deb package {}", archive.display())
.arg(archive) })?;
.stdout(Stdio::piped()); let mut archive_reader = ar::Archive::new(archive_reader);
let mut dpkg_child = dpkg // This would've been easier if `ar` crate was providing some iterator
.spawn() // over entries...
.with_context(|| format!("failed to spawn {dpkg:?}"))?; let mut inner_archive = None;
let Child { stdout, .. } = &mut dpkg_child; while let Some(entry) = archive_reader.next_entry() {
let stdout = stdout.take().unwrap(); let mut entry = entry.with_context(|| {
let mut archive_reader = tar::Archive::new(stdout); format!(
archive_reader.unpack(&archive_dir).with_context(|| { "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 _ = 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!( format!(
"failed to unpack archive {} to {}", "failed to unpack archive {} to {}",
archive.display(), archive.display(),
archive_dir.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 kernel_images = Vec::new();
let mut configs = Vec::new(); let mut configs = Vec::new();

Loading…
Cancel
Save