()
| 71 | } |
| 72 | |
| 73 | fn install_git_macos() -> Result<()> { |
| 74 | // Download official macOS git installer |
| 75 | let install_dir = git_install_dir(); |
| 76 | let bin_dir = install_dir.join("bin"); |
| 77 | let git_path = bin_dir.join("git"); |
| 78 | |
| 79 | // If already installed, just verify |
| 80 | if git_path.exists() { |
| 81 | return Ok(()); |
| 82 | } |
| 83 | |
| 84 | std::fs::create_dir_all(&bin_dir)?; |
| 85 | |
| 86 | // Download git-2.39.3-arm64-bin.tar.gz (Apple Silicon) |
| 87 | // and git-2.39.3-x86_64-bin.tar.gz (Intel) |
| 88 | let arch = if std::process::Command::new("uname") |
| 89 | .arg("-m") |
| 90 | .output() |
| 91 | .map(|o| String::from_utf8_lossy(&o.stdout).contains("arm")) |
| 92 | .unwrap_or(false) |
| 93 | { |
| 94 | "arm64" |
| 95 | } else { |
| 96 | "x86_64" |
| 97 | }; |
| 98 | |
| 99 | let tarball_name = format!("git-2.39.3-{}-bin.tar.gz", arch); |
| 100 | let download_url = format!("https://git-scm.com/download/mac/{}", tarball_name); |
| 101 | |
| 102 | let temp_tarball = std::env::temp_dir().join(&tarball_name); |
| 103 | |
| 104 | // Download with retry |
| 105 | download_with_curl(&download_url, &temp_tarball)?; |
| 106 | |
| 107 | // Extract tarball |
| 108 | let output = Command::new("tar") |
| 109 | .args([ |
| 110 | "-xzf", |
| 111 | &temp_tarball.display().to_string(), |
| 112 | "-C", |
| 113 | &bin_dir.display().to_string(), |
| 114 | ]) |
| 115 | .output()?; |
| 116 | |
| 117 | if !output.status.success() { |
| 118 | // Try alternative extraction |
| 119 | let output = Command::new("bash") |
| 120 | .args([ |
| 121 | "-c", |
| 122 | &format!( |
| 123 | "cd {} && tar -xzf {}", |
| 124 | bin_dir.display(), |
| 125 | temp_tarball.display() |
| 126 | ), |
| 127 | ]) |
| 128 | .output()?; |
| 129 | |
| 130 | if !output.status.success() { |
no test coverage detected