use std::io;
use std::path::Path;
use console::style;
use crate::config::{GrovConfig, WorktreeConfig, write_config};
use crate::git::executor::run_git_ok;
use crate::git::repo::default_branch;
use crate::git::worktree::add_worktree;
use crate::paths::{repo_name_from_url, worktree_dir};
use crate::ui::prompt;
pub fn execute(
url: Option<&str>,
name: Option<&str>,
prefix: Option<&str>,
branch: Option<&str>,
path: Option<&Path>,
) -> anyhow::Result<()> {
let stdin = io::stdin();
let mut reader = stdin.lock();
let url = match url {
Some(u) => u.to_string(),
None => {
let line = prompt("Repository URL", None, &mut reader)?;
if line.is_empty() {
anyhow::bail!("URL is required");
}
line
}
};
let derived_name = repo_name_from_url(&url);
let project_name = match name {
Some(n) => n.to_string(),
None => {
let line = prompt("Project name", Some(&derived_name), &mut reader)?;
if line.is_empty() { derived_name } else { line }
}
};
let prefix = match prefix {
Some(p) => p.to_string(),
None => prompt(
"Worktree prefix (e.g. short alias, blank for none)",
Some(""),
&mut reader,
)?,
};
let parent = match path {
Some(p) => p.to_path_buf(),
None => std::env::current_dir()?,
};
let project_dir = parent.join(&project_name);
if project_dir.exists() {
anyhow::bail!("directory already exists: {}", project_dir.display());
}
std::fs::create_dir_all(&project_dir)?;
let bare_path = project_dir.join("repo.git");
let bare_str = bare_path.to_string_lossy().to_string();
run_git_ok(None, &["clone", "--bare", &url, &bare_str])?;
let config = GrovConfig {
worktree: WorktreeConfig {
prefix: prefix.clone(),
},
};
write_config(&bare_path, &config)?;
run_git_ok(
Some(&bare_path),
&[
"config",
"remote.origin.fetch",
"+refs/heads/*:refs/remotes/origin/*",
],
)?;
run_git_ok(Some(&bare_path), &["fetch", "origin"])?;
let detected = match default_branch(&bare_path) {
Ok(branch) => branch,
Err(e) => {
eprintln!(
"{} Could not detect default branch ({}), assuming \"main\"",
style("!").yellow().bold(),
e
);
"main".to_string()
}
};
let branch = match branch {
Some(b) => b.to_string(),
None => {
let line = prompt("Default branch", Some(&detected), &mut reader)?;
if line.is_empty() { detected } else { line }
}
};
let wt_path = worktree_dir(&bare_path, &branch, &prefix);
add_worktree(&bare_path, &wt_path, Some(&branch), &[])?;
println!(
"\n{} Initialized {}/\n\n {:<12}{}\n {:<12}{}",
style("✓").green().bold(),
style(&project_name).bold(),
"bare repo",
style(format!("{}/repo.git", project_name)).dim(),
"worktree",
style(
wt_path
.file_name()
.map(|n| format!("{}/{}", project_name, n.to_string_lossy()))
.expect("worktree path must have a file name")
)
.dim(),
);
Ok(())
}