cloneRepo clones a git repo to a temp directory (shallow clone)
(url string, repoName string)
| 795 | |
| 796 | // cloneRepo clones a git repo to a temp directory (shallow clone) |
| 797 | func cloneRepo(url string, repoName string) (string, error) { |
| 798 | // Normalize URL |
| 799 | if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") { |
| 800 | url = "https://" + url |
| 801 | } |
| 802 | |
| 803 | // Create temp dir |
| 804 | tempDir, err := os.MkdirTemp("", "codemap-") |
| 805 | if err != nil { |
| 806 | return "", fmt.Errorf("failed to create temp dir: %w", err) |
| 807 | } |
| 808 | |
| 809 | // Only animate if stderr is a real terminal |
| 810 | isTTY := terminalChecker(os.Stderr) |
| 811 | |
| 812 | var done chan bool |
| 813 | if isTTY { |
| 814 | anim := render.NewCloneAnimation(os.Stderr, repoName) |
| 815 | done = make(chan bool) |
| 816 | go func() { |
| 817 | progress := 0 |
| 818 | for { |
| 819 | select { |
| 820 | case <-done: |
| 821 | // Clear the line completely when done |
| 822 | fmt.Fprint(os.Stderr, "\r\033[K") |
| 823 | return |
| 824 | default: |
| 825 | anim.Render(progress) |
| 826 | if progress < 95 { |
| 827 | progress++ |
| 828 | } |
| 829 | time.Sleep(50 * time.Millisecond) |
| 830 | } |
| 831 | } |
| 832 | }() |
| 833 | } |
| 834 | |
| 835 | // Shallow clone (quiet) |
| 836 | cmd := execCommand("git", "clone", "--depth", "1", "--single-branch", "-q", url, tempDir) |
| 837 | cloneErr := cmd.Run() |
| 838 | |
| 839 | if isTTY { |
| 840 | done <- true |
| 841 | time.Sleep(50 * time.Millisecond) // Let animation finish |
| 842 | } |
| 843 | |
| 844 | if cloneErr != nil { |
| 845 | os.RemoveAll(tempDir) |
| 846 | return "", fmt.Errorf("git clone failed: %w", cloneErr) |
| 847 | } |
| 848 | |
| 849 | return tempDir, nil |
| 850 | } |
| 851 | |
| 852 | // isTerminal checks if a file is a terminal |
| 853 | func isTerminal(f *os.File) bool { |