use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::{
action::{ActionError, Context},
action_impl::ActionImpl,
vdrive::VirtualDriveBuilder,
};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TarCreate {
archive: PathBuf,
directory: PathBuf,
}
impl TarCreate {
pub fn new(archive: PathBuf, directory: PathBuf) -> Self {
Self { archive, directory }
}
}
impl ActionImpl for TarCreate {
fn execute(&self, _context: &mut Context) -> Result<(), ActionError> {
VirtualDriveBuilder::default()
.filename(&self.archive)
.root_directory(&self.directory)
.create()
.map_err(|e| TarError::TarCreate(self.archive.clone(), self.directory.clone(), e))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TarExtract {
archive: PathBuf,
directory: PathBuf,
}
impl TarExtract {
pub fn new(archive: PathBuf, directory: PathBuf) -> Self {
Self { archive, directory }
}
}
impl ActionImpl for TarExtract {
fn execute(&self, _context: &mut Context) -> Result<(), ActionError> {
let tar = VirtualDriveBuilder::default()
.filename(&self.archive)
.root_directory(&self.directory)
.open()
.map_err(|e| TarError::TarOpen(self.archive.clone(), e))?;
tar.extract_to(&self.directory)
.map_err(|e| TarError::TarExtract(self.archive.clone(), self.directory.clone(), e))?;
Ok(())
}
}
#[derive(Debug, thiserror::Error)]
pub enum TarError {
#[error("failed to create tar archive {0} from {1}")]
TarCreate(PathBuf, PathBuf, #[source] crate::vdrive::VirtualDriveError),
#[error("failed to open tar archive {0}")]
TarOpen(PathBuf, #[source] crate::vdrive::VirtualDriveError),
#[error("failed to extract tar archive {0} into {1}")]
TarExtract(PathBuf, PathBuf, #[source] crate::vdrive::VirtualDriveError),
}
impl From<TarError> for ActionError {
fn from(value: TarError) -> Self {
Self::Tar(value)
}
}
#[cfg(test)]
mod test {
use crate::{
action::{RunnableAction, UnsafeAction},
plan::RunnablePlan,
runlog::RunLog,
};
use super::*;
use tempfile::tempdir;
fn plan() -> RunnablePlan {
let mut plan = RunnablePlan::default();
plan.set_cache_dir("/tmp");
plan.set_deps_dir("/tmp");
plan.set_source_dir("/tmp");
plan.set_artifacts_dir("/tmp");
plan
}
#[test]
fn tar_create_action() -> Result<(), Box<dyn std::error::Error>> {
let tmp = tempdir()?;
let src = tmp.path().join("src");
let tar = tmp.path().join("src.tar");
std::fs::create_dir(&src)?;
let action = RunnableAction::from_unsafe_action(&UnsafeAction::tar_create(&tar, &src));
let plan = plan();
let mut runlog = RunLog::default();
let mut context = Context::new(&mut runlog);
context.set_envs_from_plan(&plan)?;
assert!(!tar.exists());
assert!(action.execute(&mut context).is_ok());
assert!(tar.exists());
Ok(())
}
#[test]
fn tar_extract_action() -> Result<(), Box<dyn std::error::Error>> {
let tmp = tempdir()?;
let src = tmp.path().join("src");
let tar = tmp.path().join("src.tar");
let extracted = tmp.path().join("extracted");
std::fs::create_dir(&src)?;
std::fs::File::create(src.join("file.dat"))?;
let plan = plan();
let mut runlog = RunLog::default();
let mut context = Context::new(&mut runlog);
context.set_envs_from_plan(&plan)?;
RunnableAction::from_unsafe_action(&UnsafeAction::tar_create(&tar, &src))
.execute(&mut context)?;
let action =
RunnableAction::from_unsafe_action(&UnsafeAction::tar_extract(&tar, &extracted));
assert!(action.execute(&mut context).is_ok());
assert!(extracted.join("file.dat").exists());
Ok(())
}
}