thoughts_tool/git/
clone.rs1use anyhow::{Context, Result};
2use colored::*;
3use std::path::PathBuf;
4
5use crate::git::progress::InlineProgress;
6
7pub struct CloneOptions {
8 pub url: String,
9 pub target_path: PathBuf,
10 pub branch: Option<String>,
11}
12
13pub fn clone_repository(options: &CloneOptions) -> Result<()> {
14 println!("{} {}", "Cloning".green(), options.url);
15 println!(" to: {}", options.target_path.display());
16
17 if let Some(parent) = options.target_path.parent() {
19 std::fs::create_dir_all(parent).context("Failed to create clone directory")?;
20 }
21
22 if options.target_path.exists() {
24 let entries = std::fs::read_dir(&options.target_path)?;
25 if entries.count() > 0 {
26 anyhow::bail!(
27 "Target directory is not empty: {}",
28 options.target_path.display()
29 );
30 }
31 }
32
33 unsafe {
35 gix::interrupt::init_handler(1, || {}).ok();
36 }
37
38 let url = gix::url::parse(options.url.as_str().into())
39 .with_context(|| format!("Invalid repository URL: {}", options.url))?;
40
41 let mut prepare =
42 gix::prepare_clone(url, &options.target_path).context("Failed to prepare clone")?;
43
44 if let Some(branch) = &options.branch {
45 prepare = prepare
46 .with_ref_name(Some(branch.as_str()))
47 .context("Failed to set target branch")?;
48 }
49
50 let (mut checkout, _fetch_outcome) = prepare
51 .fetch_then_checkout(
52 InlineProgress::new("progress"),
53 &gix::interrupt::IS_INTERRUPTED,
54 )
55 .context("Fetch failed")?;
56
57 let (_repo, _outcome) = checkout
58 .main_worktree(
59 InlineProgress::new("checkout"),
60 &gix::interrupt::IS_INTERRUPTED,
61 )
62 .context("Checkout failed")?;
63
64 println!("\n{} Clone completed successfully", "✓".green());
65 Ok(())
66}