use std::path::{Path, PathBuf};
use tracing::info;
use crate::images::Alpine;
use crate::runner::{RunOption, Runner, RunnerError};
use crate::{Volume, VolumeName};
#[derive(Debug, thiserror::Error)]
pub enum CopyError {
#[error(transparent)]
RunnerError(#[from] RunnerError),
#[error("Path {0:?} doest not exists in host")]
PathNotExists(PathBuf),
#[error("Path {0:?} doest not have parent")]
PathWithoutParent(PathBuf),
#[error("Path {0:?} doest not have a name")]
PathWithoutName(PathBuf),
}
impl Runner {
#[tracing::instrument(skip(self, path), fields(path = ?path.as_ref()))]
pub async fn copy_to_volume(
&self,
volume: VolumeName,
path: impl AsRef<Path>,
) -> Result<(), CopyError> {
let path = path.as_ref();
if !path.exists() {
return Err(CopyError::PathNotExists(path.to_path_buf()));
}
let Some(parent) = path.parent() else {
return Err(CopyError::PathWithoutParent(path.to_path_buf()));
};
let Some(file_name) = path.file_name().and_then(|it| it.to_str()) else {
return Err(CopyError::PathWithoutName(path.to_path_buf()));
};
let source = format!("/source/{file_name}");
let cmds = if path.is_dir() {
vec!["cp", "-R", &source, "/dest"]
} else {
vec!["cp", &source, "/dest"]
};
let options = RunOption::builder()
.with_volumes([
Volume::bind_mount(parent, "/source"),
Volume::container_volume(volume.clone(), "/dest"),
])
.with_command(cmds)
.build();
let _container = self.start_with_options(Alpine, options).await?;
info!("{path:?} copied into {volume}");
Ok(())
}
}