use crate::config::{get_biovault_home, is_syftbox_env, Config};
use crate::Result;
use dialoguer::{theme::ColorfulTheme, Confirm, Input};
use std::env;
use std::fs;
use std::io::IsTerminal;
use tracing::info;
pub async fn execute(email: Option<&str>) -> Result<()> {
let biovault_dir = get_biovault_home()?;
let email = if let Some(email) = email {
email.to_string()
} else if let Ok(syftbox_email) = env::var("SYFTBOX_EMAIL") {
if std::io::stdin().is_terminal() {
println!("Detected SyftBox environment email: {}", syftbox_email);
let use_syftbox = Confirm::with_theme(&ColorfulTheme::default())
.with_prompt("Use this email for BioVault?")
.default(true)
.interact()
.map_err(|e| anyhow::anyhow!("Prompt error: {}", e))?;
if use_syftbox {
syftbox_email
} else {
Input::with_theme(&ColorfulTheme::default())
.with_prompt("Enter email address")
.interact_text()
.map_err(|e| anyhow::anyhow!("Prompt error: {}", e))?
}
} else {
syftbox_email
}
} else if std::io::stdin().is_terminal() {
Input::with_theme(&ColorfulTheme::default())
.with_prompt("Enter email address")
.interact_text()
.map_err(|e| anyhow::anyhow!("Prompt error: {}", e))?
} else {
return Err(anyhow::anyhow!(
"email is required. Provide as 'bv init <email>' or set SYFTBOX_EMAIL"
)
.into());
};
if !biovault_dir.exists() {
fs::create_dir_all(&biovault_dir)?;
info!("Created directory: {:?}", biovault_dir);
}
let config_file = biovault_dir.join("config.yaml");
if config_file.exists() {
println!(
"Configuration file already exists at: {}",
config_file.display()
);
println!("Skipping initialization.");
} else {
if is_syftbox_env() {
println!("✓ Running in SyftBox virtualenv");
if let Ok(data_dir) = env::var("SYFTBOX_DATA_DIR") {
println!(" SyftBox data directory: {}", data_dir);
}
println!(" BioVault home: {}", biovault_dir.display());
}
let syftbox_config = if let Ok(config_path) = env::var("SYFTBOX_CONFIG_PATH") {
if std::path::Path::new(&config_path).exists() {
println!("✓ Detected SyftBox config at: {}", config_path);
Some(config_path)
} else {
None
}
} else {
let home_dir = dirs::home_dir()
.ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;
let default_syftbox = home_dir.join(".syftbox").join("config.json");
if default_syftbox.exists() {
Some(default_syftbox.to_string_lossy().to_string())
} else {
None
}
};
let config = Config {
email: email.to_string(),
syftbox_config: syftbox_config.clone(),
version: Some("0.1.16".to_string()),
};
config.save(&config_file)?;
println!("✓ BioVault initialized successfully!");
println!(" Configuration saved to: {}", config_file.display());
println!(" Email: {}", email);
if let Some(ref syftbox_cfg) = syftbox_config {
println!(" SyftBox config: {}", syftbox_cfg);
}
let env_dir = biovault_dir.join("env");
if !env_dir.exists() {
fs::create_dir_all(&env_dir)?;
info!("Created environment directory: {:?}", env_dir);
}
let default_dir = env_dir.join("default");
if !default_dir.exists() {
fs::create_dir_all(&default_dir)?;
info!("Created default template directory: {:?}", default_dir);
}
let template_nf_content = include_str!("../../templates/default/template.nf");
let template_nf_path = default_dir.join("template.nf");
fs::write(&template_nf_path, template_nf_content)?;
info!("Created template.nf at: {:?}", template_nf_path);
let nextflow_config_content = include_str!("../../templates/default/nextflow.config");
let nextflow_config_path = default_dir.join("nextflow.config");
fs::write(&nextflow_config_path, nextflow_config_content)?;
info!("Created nextflow.config at: {:?}", nextflow_config_path);
let snp_dir = env_dir.join("snp");
if !snp_dir.exists() {
fs::create_dir_all(&snp_dir)?;
info!("Created SNP template directory: {:?}", snp_dir);
}
let snp_template_nf_content = include_str!("../../templates/snp/template.nf");
let snp_template_nf_path = snp_dir.join("template.nf");
fs::write(&snp_template_nf_path, snp_template_nf_content)?;
info!("Created SNP template.nf at: {:?}", snp_template_nf_path);
let snp_nextflow_config_content = include_str!("../../templates/snp/nextflow.config");
let snp_nextflow_config_path = snp_dir.join("nextflow.config");
fs::write(&snp_nextflow_config_path, snp_nextflow_config_content)?;
info!(
"Created SNP nextflow.config at: {:?}",
snp_nextflow_config_path
);
println!("✓ Nextflow templates installed:");
println!(" - Default templates: {}", default_dir.display());
println!(" - SNP templates: {}", snp_dir.display());
match config.get_syftbox_data_dir() {
Ok(data_dir) => {
let app = crate::syftbox::SyftBoxApp::new(&data_dir, &config.email, "biovault")?;
let _ = app.register_endpoint("/message")?;
println!(
"✓ SyftBox RPC initialized for messaging at: {}",
app.rpc_dir.display()
);
}
Err(e) => {
println!(
"⚠️ Skipped SyftBox RPC init (no data dir): {}\n Hint: set SYFTBOX_DATA_DIR or configure ~/.syftbox/config.json and re-run 'bv init'",
e
);
}
}
}
Ok(())
}