use anyhow::{Context, anyhow, bail};
use dolly_cli::{binary, build, git, paths, recipe::Recipe, ui};
pub fn handle(name: &str) -> anyhow::Result<()> {
let (owner, repo) = name
.split_once('/')
.filter(|(o, n)| !o.is_empty() && !n.is_empty() && !n.contains('/'))
.ok_or_else(|| anyhow!("repo must be in `owner/repo` form"))?;
let recipe = Recipe::find(repo).with_context(|| format!("loading recipe for `{repo}`"))?;
if recipe.package.slug() != name {
bail!(
"recipe declares `{}` but CLI input is `{name}`",
recipe.package.slug()
);
}
let repositories_dir = paths::repositories_dir()?;
let repo_path = repositories_dir.join(repo);
if !repo_path.exists() {
ui::status("Cloning", name);
std::fs::create_dir_all(&repositories_dir)
.with_context(|| format!("creating {}", repositories_dir.display()))?;
let url = format!("https://github.com/{owner}/{repo}.git");
git::clone(&url, &repo_path).with_context(|| format!("cloning `{name}`"))?;
} else {
ui::status("Cached", name);
}
ui::status("Building", name);
build::run(&recipe.build.steps, &repo_path).with_context(|| format!("building `{name}`"))?;
let binary_path = repo_path.join(&recipe.build.output);
let bin_name = binary_path
.file_name()
.ok_or_else(|| anyhow!("`build.output` has no filename"))?;
let install_path = paths::default_install_dir()?.join(bin_name);
binary::place(&binary_path, &install_path).with_context(|| format!("installing `{name}`"))?;
binary::make_executable(&install_path)
.with_context(|| format!("setting executable bit on {}", install_path.display()))?;
ui::status(
"Installed",
&format!("{repo} to {}", install_path.display()),
);
Ok(())
}