use crate::{config::Config, error::Result};
use anyhow::Context;
use std::fs;
use std::io::{self, Write};
use std::path::PathBuf;
const PROJECT_YAML_TEMPLATE: &str = include_str!("../../templates/project.yaml");
const WORKFLOW_NF_TEMPLATE: &str = include_str!("../../templates/workflow.nf");
pub async fn create(name: Option<String>, folder: Option<String>) -> Result<()> {
let project_name = match name {
Some(n) => n,
None => {
print!("Project name: ");
io::stdout().flush()?;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
input.trim().to_string()
}
};
if project_name.is_empty() {
return Err(anyhow::anyhow!("Project name cannot be empty").into());
}
let project_dir = match folder {
Some(f) => PathBuf::from(f),
None => {
let cwd = std::env::current_dir().context("Failed to get current working directory")?;
let default_path = cwd.join(&project_name);
println!("Project will be created at: {}", default_path.display());
print!("Continue? [Y/n]: ");
io::stdout().flush()?;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
let input = input.trim().to_lowercase();
if input.is_empty() || input == "y" || input == "yes" {
default_path
} else if input == "n" || input == "no" {
print!("Enter custom path: ");
io::stdout().flush()?;
let mut custom_path = String::new();
io::stdin().read_line(&mut custom_path)?;
PathBuf::from(custom_path.trim())
} else {
return Err(
anyhow::anyhow!("Invalid response. Please run the command again.").into(),
);
}
}
};
if project_dir.exists() {
return Err(anyhow::anyhow!(
"Folder '{}' already exists. Please choose a different name or location.",
project_dir.display()
)
.into());
}
let config_file = crate::config::Config::get_config_path()?;
let email = if config_file.exists() {
let config = Config::from_file(&config_file)?;
config.email
} else {
return Err(anyhow::anyhow!(
"BioVault not initialized. Please run 'bv init <email>' first"
)
.into());
};
println!("Creating project '{}'...", project_name);
fs::create_dir_all(&project_dir).with_context(|| {
format!(
"Failed to create project directory: {}",
project_dir.display()
)
})?;
let assets_dir = project_dir.join("assets");
fs::create_dir_all(&assets_dir).with_context(|| {
format!(
"Failed to create assets directory: {}",
assets_dir.display()
)
})?;
let project_yaml_content = PROJECT_YAML_TEMPLATE
.replace("{project_name}", &project_name)
.replace("{email}", &email);
let project_yaml_path = project_dir.join("project.yaml");
fs::write(&project_yaml_path, project_yaml_content).with_context(|| {
format!(
"Failed to write project.yaml: {}",
project_yaml_path.display()
)
})?;
let workflow_path = project_dir.join("workflow.nf");
fs::write(&workflow_path, WORKFLOW_NF_TEMPLATE)
.with_context(|| format!("Failed to write workflow.nf: {}", workflow_path.display()))?;
println!(
"✓ Project created successfully at: {}",
project_dir.display()
);
let folder_name = project_dir
.file_name()
.and_then(|n| n.to_str())
.unwrap_or(&project_name);
println!("\nProject structure:");
println!(" {}/", folder_name);
println!(" ├── project.yaml");
println!(" ├── assets/");
println!(" └── workflow.nf");
Ok(())
}