use std::{
path::{Path, PathBuf},
process::Command,
};
use clingwrap::runner::{CommandError, CommandRunner};
pub fn convert_image(original: &Path, new: &Path) -> Result<(), QemuUtilError> {
let mut cmd = Command::new("qemu-img");
cmd.arg("convert")
.arg(original)
.args(["-O", "qcow2"])
.arg(new);
let mut runner = CommandRunner::new(cmd);
runner.capture_stdout();
runner.capture_stderr();
runner
.execute()
.map_err(|err| QemuUtilError::convert(original, new, err))?;
Ok(())
}
pub fn create_cow_image(backing_file: &Path, new_file: &Path) -> Result<(), QemuUtilError> {
let mut cmd = Command::new("qemu-img");
cmd.arg("create")
.arg("-b")
.arg(backing_file)
.args(["-F", "qcow2"])
.args(["-f", "qcow2"])
.arg(new_file);
let mut runner = CommandRunner::new(cmd);
runner.capture_stdout();
runner.capture_stderr();
let result = runner.execute();
match &result {
Ok(_) => (),
Err(CommandError::CommandFailed { output, .. }) => {
eprintln!("{}", String::from_utf8_lossy(&output.stderr));
result.map_err(|err| QemuUtilError::cow(new_file, backing_file, err))?;
}
_ => panic!("{result:#?}"),
}
Ok(())
}
#[allow(missing_docs)]
#[derive(Debug, thiserror::Error)]
pub enum QemuUtilError {
#[error("failed to run qemu-img convert {0} to {1}")]
Convert(PathBuf, PathBuf, #[source] Box<CommandError>),
#[error("failed to run qemu-img to create a copy-on-write file {0}, backing on {1}")]
COW(PathBuf, PathBuf, #[source] Box<CommandError>),
}
impl QemuUtilError {
fn convert(original: &Path, new: &Path, err: CommandError) -> Self {
Self::Convert(original.to_path_buf(), new.to_path_buf(), Box::new(err))
}
fn cow(original: &Path, new: &Path, err: CommandError) -> Self {
Self::COW(original.to_path_buf(), new.to_path_buf(), Box::new(err))
}
}