thoughts_tool/git/
clone.rs

1use 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    // Ensure parent directory exists
18    if let Some(parent) = options.target_path.parent() {
19        std::fs::create_dir_all(parent).context("Failed to create clone directory")?;
20    }
21
22    // Ensure target directory is empty
23    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    // SAFETY: progress handler is lock-free and alloc-minimal
34    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}