feat: add basic plan and project clone
Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
120
crates/cuddle/src/plan.rs
Normal file
120
crates/cuddle/src/plan.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use fs_extra::dir::CopyOptions;
|
||||
|
||||
use crate::project::{self, ProjectPlan};
|
||||
|
||||
pub const CUDDLE_PLAN_FOLDER: &str = "plan";
|
||||
pub const CUDDLE_PROJECT_WORKSPACE: &str = ".cuddle";
|
||||
|
||||
pub trait PlanPathExt {
|
||||
fn plan_path(&self) -> PathBuf;
|
||||
}
|
||||
|
||||
impl PlanPathExt for project::ProjectPlan {
|
||||
fn plan_path(&self) -> PathBuf {
|
||||
self.root
|
||||
.join(CUDDLE_PROJECT_WORKSPACE)
|
||||
.join(CUDDLE_PLAN_FOLDER)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Plan {}
|
||||
|
||||
impl Plan {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
pub async fn clone_from_project(
|
||||
&self,
|
||||
project: &ProjectPlan,
|
||||
) -> anyhow::Result<Option<ClonedPlan>> {
|
||||
if !project.plan_path().exists() {
|
||||
if project.has_plan() {
|
||||
self.prepare_plan(project).await?;
|
||||
}
|
||||
|
||||
match project.get_plan() {
|
||||
project::Plan::None => Ok(None),
|
||||
project::Plan::Git(url) => Ok(Some(self.git_plan(project, url).await?)),
|
||||
project::Plan::Folder(folder) => {
|
||||
Ok(Some(self.folder_plan(project, &folder).await?))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match project.get_plan() {
|
||||
project::Plan::Folder(folder) => {
|
||||
self.clean_plan(project).await?;
|
||||
self.prepare_plan(project).await?;
|
||||
|
||||
Ok(Some(self.folder_plan(project, &folder).await?))
|
||||
}
|
||||
project::Plan::Git(_git) => Ok(Some(ClonedPlan {})),
|
||||
project::Plan::None => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn prepare_plan(&self, project: &ProjectPlan) -> anyhow::Result<()> {
|
||||
tracing::trace!("preparing workspace");
|
||||
|
||||
tokio::fs::create_dir_all(project.plan_path()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn clean_plan(&self, project: &ProjectPlan) -> anyhow::Result<()> {
|
||||
tracing::trace!("clean plan");
|
||||
|
||||
tokio::fs::remove_dir_all(project.plan_path()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn git_plan(&self, project: &ProjectPlan, url: String) -> anyhow::Result<ClonedPlan> {
|
||||
let mut cmd = tokio::process::Command::new("git");
|
||||
cmd.args(["clone", &url, &project.plan_path().display().to_string()]);
|
||||
|
||||
tracing::debug!(url = url, "cloning git plan");
|
||||
|
||||
let output = cmd.output().await?;
|
||||
if !output.status.success() {
|
||||
anyhow::bail!(
|
||||
"failed to clone: {}, output: {} {}",
|
||||
url,
|
||||
std::str::from_utf8(&output.stdout)?,
|
||||
std::str::from_utf8(&output.stderr)?,
|
||||
)
|
||||
}
|
||||
|
||||
Ok(ClonedPlan {})
|
||||
}
|
||||
|
||||
async fn folder_plan(&self, project: &ProjectPlan, path: &Path) -> anyhow::Result<ClonedPlan> {
|
||||
tracing::trace!(
|
||||
src = path.display().to_string(),
|
||||
dest = project.plan_path().display().to_string(),
|
||||
"copying src into plan dest"
|
||||
);
|
||||
|
||||
let mut items_stream = tokio::fs::read_dir(path).await?;
|
||||
let mut items = Vec::new();
|
||||
while let Some(item) = items_stream.next_entry().await? {
|
||||
items.push(item.path());
|
||||
}
|
||||
|
||||
fs_extra::copy_items(
|
||||
&items,
|
||||
project.plan_path(),
|
||||
&CopyOptions::default()
|
||||
.overwrite(true)
|
||||
.depth(0)
|
||||
.copy_inside(false),
|
||||
)?;
|
||||
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ClonedPlan {}
|
Reference in New Issue
Block a user