Skip to content

Commit 3eb78c4

Browse files
committed
refactor: share clone and install git plumbing
1 parent 3604ed0 commit 3eb78c4

2 files changed

Lines changed: 5 additions & 101 deletions

File tree

src/clone.rs

Lines changed: 4 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
pub use crate::git::{clone_to_path, get_remote_default_branch};
2+
13
use crate::config::Config;
4+
use crate::git::build_fetch_options;
25
use anyhow::{Context, Result, anyhow};
36
use git2::Repository;
47
use std::io::{self, Write};
@@ -93,86 +96,6 @@ pub fn parse_repo_url(input: &str) -> Result<String> {
9396
}
9497
}
9598

96-
pub fn get_remote_default_branch(url: &str) -> Result<String> {
97-
let temp_dir = tempfile::tempdir().context("Failed to create temporary directory")?;
98-
99-
let repository =
100-
Repository::init(temp_dir.path()).context("Failed to initialize temp repository")?;
101-
102-
let mut remote = repository
103-
.remote_anonymous(url)
104-
.context("Failed to create remote")?;
105-
106-
remote
107-
.connect(git2::Direction::Fetch)
108-
.context("Failed to connect to remote")?;
109-
110-
if let Ok(default_branch) = remote.default_branch() {
111-
remote.disconnect().context("Failed to disconnect remote")?;
112-
113-
let branch_name = default_branch
114-
.as_str()
115-
.context("Failed to read default branch name")?
116-
.trim_start_matches("refs/heads/")
117-
.to_string();
118-
119-
if !branch_name.is_empty() {
120-
return Ok(branch_name);
121-
}
122-
} else {
123-
remote.disconnect().context("Failed to disconnect remote")?;
124-
}
125-
126-
let mut fetch_options = git2::FetchOptions::new();
127-
fetch_options.download_tags(git2::AutotagOption::All);
128-
129-
let remote_name = remote.name().unwrap_or("origin");
130-
let refspec = format!("+refs/heads/*:refs/remotes/{}/*", remote_name);
131-
132-
remote
133-
.fetch(&[&refspec], Some(&mut fetch_options), None)
134-
.context("Failed to fetch from remote")?;
135-
136-
let default_branch = find_default_branch(&repository)?;
137-
138-
Ok(default_branch)
139-
}
140-
141-
fn find_default_branch(repository: &Repository) -> Result<String> {
142-
let branches = repository.branches(Some(git2::BranchType::Remote))?;
143-
144-
let mut candidates: Vec<(String, bool)> = Vec::new();
145-
146-
for branch_result in branches {
147-
let (branch, _) = branch_result.context("Failed to iterate branches")?;
148-
let name_result = branch.name().context("Failed to get branch name")?;
149-
if let Some(branch_name) = name_result {
150-
if branch_name.ends_with("/HEAD") {
151-
continue;
152-
}
153-
let is_main = branch_name == "origin/main";
154-
let is_master = branch_name == "origin/master";
155-
let is_preferred = is_main || is_master;
156-
candidates.push((branch_name.to_string(), is_preferred));
157-
}
158-
}
159-
160-
candidates.sort_by(|candidate_a, candidate_b| {
161-
let (_, a_is_preferred) = candidate_a;
162-
let (_, b_is_preferred) = candidate_b;
163-
match (a_is_preferred, b_is_preferred) {
164-
(true, false) => std::cmp::Ordering::Less,
165-
(false, true) => std::cmp::Ordering::Greater,
166-
_ => candidate_a.0.cmp(&candidate_b.0),
167-
}
168-
});
169-
170-
candidates
171-
.first()
172-
.map(|(branch_name, _)| branch_name.trim_start_matches("origin/").to_string())
173-
.ok_or_else(|| anyhow!("No branches found in remote repository"))
174-
}
175-
17699
pub fn has_unpushed_changes(path: &Path) -> bool {
177100
let repository = match Repository::open(path) {
178101
Ok(repo) => repo,
@@ -259,24 +182,6 @@ pub fn backup_existing(source: &Path) -> Result<PathBuf> {
259182
Ok(backup_path)
260183
}
261184

262-
pub fn clone_to_path(url: &str, branch: &str, target: &Path) -> Result<()> {
263-
let mut fetch_options = git2::FetchOptions::new();
264-
fetch_options.download_tags(git2::AutotagOption::All);
265-
266-
let mut builder = git2::build::RepoBuilder::new();
267-
builder.fetch_options(fetch_options);
268-
269-
if !branch.is_empty() {
270-
builder.branch(branch);
271-
}
272-
273-
builder
274-
.clone(url, target)
275-
.context(format!("Failed to clone from {}", url))?;
276-
277-
Ok(())
278-
}
279-
280185
pub fn update_existing(path: &Path) -> Result<()> {
281186
let repository = Repository::open(path).context("Failed to open existing repository")?;
282187

@@ -286,8 +191,7 @@ pub fn update_existing(path: &Path) -> Result<()> {
286191
));
287192
}
288193

289-
let mut fetch_options = git2::FetchOptions::new();
290-
fetch_options.download_tags(git2::AutotagOption::All);
194+
let mut fetch_options = build_fetch_options();
291195

292196
let remotes = repository.remotes().context("Failed to get remotes")?;
293197

src/install.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::clone::clone_to_path;
21
use crate::config::Config;
2+
use crate::git::clone_to_path;
33
use anyhow::{Context, Result, anyhow};
44
use git2::Repository;
55
use std::fs;

0 commit comments

Comments
 (0)