use crate::tools::FsTools;
use anyhow::{Result, anyhow};
use clap::ArgAction;
use mcplease::{
traits::{Tool, WithExamples},
types::Example,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, schemars::JsonSchema, clap::Args)]
#[serde(rename = "move")]
pub struct Move {
pub source: String,
pub destination: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[arg(long, action = ArgAction::SetTrue)]
pub overwrite: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
#[arg(long, action = ArgAction::SetTrue)]
pub create_directories: Option<bool>,
}
impl WithExamples for Move {
fn examples() -> Vec<Example<Self>> {
vec![
Example {
description: "Rename a new file relative to a session, creating a directory if needed",
item: Self {
source: "src/tool.rs".into(),
destination: "src/tool/mod.rs".into(),
overwrite: None,
create_directories: Some(true),
},
},
Example {
description: "Move a file, intentionally replacing the existing file",
item: Self {
source: "/some/absolute/path/src/main.rs".into(),
destination: "/some/absolute/path/src/lib.rs".into(),
overwrite: Some(true),
create_directories: None,
},
},
]
}
}
impl Move {
fn overwrite(&self) -> bool {
self.overwrite.unwrap_or_default()
}
fn create_directories(&self) -> bool {
self.create_directories.unwrap_or(true)
}
}
impl Tool<FsTools> for Move {
fn execute(self, state: &mut FsTools) -> Result<String> {
let source = state.resolve_path(&self.source, None)?;
let destination = state.resolve_path(&self.destination, None)?;
if destination.exists() && !self.overwrite() {
return Err(anyhow!(
"{} already exists, use `overwrite` to intentionally replace it",
destination.display()
));
}
if !source.exists() {
return Err(anyhow!("{} not found", source.display()));
}
if self.create_directories() {
if let Some(parent_dir) = destination.parent() {
std::fs::create_dir_all(parent_dir)?;
}
}
std::fs::rename(&source, &destination)?;
Ok(format!(
"Successfully moved {} to {}",
source.display(),
destination.display()
))
}
}