Skip to content

Commit

Permalink
lib: add type support for refspecs
Browse files Browse the repository at this point in the history
Fully qualified git refs (e.g., `+refs/head/main:refs/remotes/origin/main`)
are commonly used throughout the git glue code.

It is laborious and error prone to keep parsing refspecs when we need
only a segment of it.

This commits adds a type, `RefSpec`, which does exactly that
  • Loading branch information
bsdinis committed Jan 18, 2025
1 parent 027589d commit dc6ebe1
Showing 1 changed file with 35 additions and 1 deletion.
36 changes: 35 additions & 1 deletion lib/src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,34 @@ impl fmt::Display for RefName {
}
}

/// a refspec is formatted as <source>:<destination>
/// if it is forced, a '+' is prepended
#[derive(Debug, Hash, PartialEq, Eq)]
pub(crate) struct RefSpec {
forced: bool,
source: String,
destination: String,
}

impl RefSpec {
fn forced(source: impl Into<String>, destination: impl Into<String>) -> Self {
RefSpec {
forced: true,
source: source.into(),
destination: destination.into(),
}
}

pub(crate) fn to_git_format(&self) -> String {
format!(
"{}{}:{}",
if self.forced { "+" } else { "" },
self.source,
self.destination
)
}
}

pub fn parse_git_ref(ref_name: &str) -> Option<RefName> {
if let Some(branch_name) = ref_name.strip_prefix("refs/heads/") {
// Git CLI says 'HEAD' is not a valid branch name
Expand Down Expand Up @@ -1452,8 +1480,14 @@ impl<'a> GitFetch<'a> {
* because `to_glob()` escapes such `*`s as `[*]`. */
|glob| !glob.contains(INVALID_REFSPEC_CHARS),
)
.map(|glob| format!("+refs/heads/{glob}:refs/remotes/{remote_name}/{glob}"))
.map(|glob| {
RefSpec::forced(
format!("refs/heads/{glob}"),
format!("refs/remotes/{remote_name}/{glob}"),
)
})
})
.map(|refspec| refspec.map(|r| r.to_git_format()))
.collect::<Option<_>>()
.ok_or(GitFetchError::InvalidBranchPattern)?;
if refspecs.is_empty() {
Expand Down

0 comments on commit dc6ebe1

Please sign in to comment.