use std::{borrow::Cow, fmt::Debug};
use crate::{
conventional::commit::{CommitParser, ConventionalCommit},
error::ConvcoError,
};
#[cfg(feature = "git2")]
mod git_git2;
#[cfg(feature = "gix")]
mod git_gix;
#[cfg(feature = "git2")]
pub fn open_repo() -> Result<git2::Repository, ConvcoError> {
Repo::open()
}
#[cfg(all(not(feature = "git2"), feature = "gix"))]
pub fn open_repo() -> Result<gix::Repository, ConvcoError> {
Repo::open()
}
#[derive(Debug)]
pub struct Commit<C> {
pub conventional_commit: ConventionalCommit,
pub commit: C,
}
pub trait CommitTrait: Debug + Clone {
type ObjectId;
fn short_id(&self) -> String;
fn id(&self) -> String;
fn oid(&self) -> Self::ObjectId;
fn commit_message(&self) -> Result<Cow<'_, str>, ConvcoError>;
fn commit_time(&self) -> Result<jiff::Zoned, ConvcoError>;
}
pub type RevWalkIter<'repo, C> =
Box<dyn Iterator<Item = Result<Commit<C>, (ConvcoError, C)>> + 'repo>;
pub trait Repo<'repo>: Sized {
type CommitTrait: CommitTrait;
fn open() -> Result<Self, ConvcoError>;
fn find_last_version(
&'repo self,
commit: &Self::CommitTrait,
ignore_prereleases: bool,
semvers: &[(semver::Version, Self::CommitTrait)],
) -> Result<Option<(semver::Version, Self::CommitTrait)>, ConvcoError>;
fn revwalk(
&'repo self,
options: RevWalkOptions<'repo, Self::CommitTrait>,
) -> Result<RevWalkIter<'repo, Self::CommitTrait>, ConvcoError>;
fn semver_tags(
&'repo self,
prefix: &str,
) -> Result<Vec<(semver::Version, Self::CommitTrait)>, ConvcoError>;
fn revparse_single(&'repo self, spec: &str) -> Result<Self::CommitTrait, ConvcoError>;
fn revision_time(
&'repo self,
spec: &str,
commit: &Self::CommitTrait,
) -> Result<jiff::Zoned, ConvcoError>;
fn url(&self, remote: &str) -> Result<Option<String>, ConvcoError>;
}
macro_rules! define_max_component_iter {
($name:ident, $ext_trait:ident, $method:ident, $component:ident) => {
pub struct $name<O: CommitTrait, I: Iterator<Item = (semver::Version, O)>> {
inner: I,
max_count: u64,
current: u64,
}
pub trait $ext_trait<O: CommitTrait, I: Iterator<Item = (semver::Version, O)>> {
fn $method(self, max_count: u64) -> $name<O, I>;
}
impl<O: CommitTrait, I: Iterator<Item = (semver::Version, O)>> Iterator for $name<O, I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let next = self.inner.next()?;
if self.current == u64::MAX {
self.current = next.0.$component;
}
if next.0.$component != self.current {
self.max_count -= 1;
if self.max_count == 0 {
return None;
}
self.current = next.0.$component;
}
Some(next)
}
}
impl<I, O> $ext_trait<O, I> for I
where
I: Iterator<Item = (semver::Version, O)>,
O: CommitTrait,
{
fn $method(self, max_count: u64) -> $name<O, I> {
$name {
inner: self,
max_count,
current: u64::MAX,
}
}
}
};
}
define_max_component_iter!(MaxMajorsIter, MaxMajorsIterExt, max_majors_iter, major);
define_max_component_iter!(MaxMinorsIter, MaxMinorsIterExt, max_minors_iter, minor);
define_max_component_iter!(MaxPatchesIter, MaxPatchesIterExt, max_patches_iter, patch);
#[derive(Clone, Debug)]
pub struct RevWalkOptions<'a, C> {
pub from_rev: Vec<C>,
pub to_rev: C,
pub first_parent: bool,
pub no_merge_commits: bool,
pub no_revert_commits: bool,
pub paths: Vec<String>,
pub parser: &'a CommitParser,
}