use std::marker::PhantomData;
use git_ext::ref_format::{
self, refname,
refspec::{self, PatternString, QualifiedPattern},
Qualified, RefStr, RefString,
};
use thiserror::Error;
use crate::{Branch, Local, Namespace, Remote, Tag};
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
RefFormat(#[from] ref_format::Error),
}
#[derive(Clone, Debug)]
pub struct Glob<T> {
globs: Vec<QualifiedPattern<'static>>,
glob_type: PhantomData<T>, }
impl<T> Default for Glob<T> {
fn default() -> Self {
Self {
globs: Default::default(),
glob_type: PhantomData,
}
}
}
impl<T> Glob<T> {
pub fn globs(&self) -> impl Iterator<Item = &QualifiedPattern<'static>> {
self.globs.iter()
}
pub fn and(mut self, other: impl Into<Self>) -> Self {
self.globs.extend(other.into().globs);
self
}
}
impl Glob<Namespace> {
pub fn all_namespaces() -> Self {
Self::namespaces(refspec::pattern!("*"))
}
pub fn namespaces(glob: PatternString) -> Self {
let globs = vec![Self::qualify(glob)];
Self {
globs,
glob_type: PhantomData,
}
}
pub fn insert(mut self, glob: PatternString) -> Self {
self.globs.push(Self::qualify(glob));
self
}
fn qualify(glob: PatternString) -> QualifiedPattern<'static> {
qualify(&refname!("refs/namespaces"), glob).expect("BUG: pattern is qualified")
}
}
impl FromIterator<PatternString> for Glob<Namespace> {
fn from_iter<T: IntoIterator<Item = PatternString>>(iter: T) -> Self {
let globs = iter
.into_iter()
.map(|pat| {
qualify(&refname!("refs/namespaces"), pat).expect("BUG: pattern is qualified")
})
.collect();
Self {
globs,
glob_type: PhantomData,
}
}
}
impl Extend<PatternString> for Glob<Namespace> {
fn extend<T: IntoIterator<Item = PatternString>>(&mut self, iter: T) {
self.globs.extend(iter.into_iter().map(|pat| {
qualify(&refname!("refs/namespaces"), pat).expect("BUG: pattern is qualified")
}))
}
}
impl Glob<Tag> {
pub fn all_tags() -> Self {
Self::tags(refspec::pattern!("*"))
}
pub fn tags(glob: PatternString) -> Self {
let globs = vec![Self::qualify(glob)];
Self {
globs,
glob_type: PhantomData,
}
}
pub fn insert(mut self, glob: PatternString) -> Self {
self.globs.push(Self::qualify(glob));
self
}
fn qualify(glob: PatternString) -> QualifiedPattern<'static> {
qualify(&refname!("refs/tags"), glob).expect("BUG: pattern is qualified")
}
}
impl FromIterator<PatternString> for Glob<Tag> {
fn from_iter<T: IntoIterator<Item = PatternString>>(iter: T) -> Self {
let globs = iter
.into_iter()
.map(|pat| qualify(&refname!("refs/tags"), pat).expect("BUG: pattern is qualified"))
.collect();
Self {
globs,
glob_type: PhantomData,
}
}
}
impl Extend<PatternString> for Glob<Tag> {
fn extend<T: IntoIterator<Item = PatternString>>(&mut self, iter: T) {
self.globs.extend(
iter.into_iter()
.map(|pat| qualify(&refname!("refs/tag"), pat).expect("BUG: pattern is qualified")),
)
}
}
impl Glob<Local> {
pub fn all_heads() -> Self {
Self::heads(refspec::pattern!("*"))
}
pub fn heads(glob: PatternString) -> Self {
let globs = vec![Self::qualify_heads(glob)];
Self {
globs,
glob_type: PhantomData,
}
}
pub fn insert(mut self, glob: PatternString) -> Self {
self.globs.push(Self::qualify_heads(glob));
self
}
pub fn branches(self) -> Glob<Branch> {
self.into()
}
fn qualify_heads(glob: PatternString) -> QualifiedPattern<'static> {
qualify(&refname!("refs/heads"), glob).expect("BUG: pattern is qualified")
}
}
impl FromIterator<PatternString> for Glob<Local> {
fn from_iter<T: IntoIterator<Item = PatternString>>(iter: T) -> Self {
let globs = iter
.into_iter()
.map(|pat| qualify(&refname!("refs/heads"), pat).expect("BUG: pattern is qualified"))
.collect();
Self {
globs,
glob_type: PhantomData,
}
}
}
impl Extend<PatternString> for Glob<Local> {
fn extend<T: IntoIterator<Item = PatternString>>(&mut self, iter: T) {
self.globs.extend(
iter.into_iter().map(|pat| {
qualify(&refname!("refs/heads"), pat).expect("BUG: pattern is qualified")
}),
)
}
}
impl From<Glob<Local>> for Glob<Branch> {
fn from(Glob { globs, .. }: Glob<Local>) -> Self {
Self {
globs,
glob_type: PhantomData,
}
}
}
impl Glob<Remote> {
pub fn all_remotes() -> Self {
Self::remotes(refspec::pattern!("*"))
}
pub fn remotes(glob: PatternString) -> Self {
let globs = vec![Self::qualify_remotes(glob)];
Self {
globs,
glob_type: PhantomData,
}
}
pub fn insert(mut self, glob: PatternString) -> Self {
self.globs.push(Self::qualify_remotes(glob));
self
}
pub fn branches(self) -> Glob<Branch> {
self.into()
}
fn qualify_remotes(glob: PatternString) -> QualifiedPattern<'static> {
qualify(&refname!("refs/remotes"), glob).expect("BUG: pattern is qualified")
}
}
impl FromIterator<PatternString> for Glob<Remote> {
fn from_iter<T: IntoIterator<Item = PatternString>>(iter: T) -> Self {
let globs = iter
.into_iter()
.map(|pat| qualify(&refname!("refs/remotes"), pat).expect("BUG: pattern is qualified"))
.collect();
Self {
globs,
glob_type: PhantomData,
}
}
}
impl Extend<PatternString> for Glob<Remote> {
fn extend<T: IntoIterator<Item = PatternString>>(&mut self, iter: T) {
self.globs.extend(
iter.into_iter().map(|pat| {
qualify(&refname!("refs/remotes"), pat).expect("BUG: pattern is qualified")
}),
)
}
}
impl From<Glob<Remote>> for Glob<Branch> {
fn from(Glob { globs, .. }: Glob<Remote>) -> Self {
Self {
globs,
glob_type: PhantomData,
}
}
}
impl Glob<Qualified<'_>> {
pub fn all_category<R: AsRef<RefStr>>(category: R) -> Self {
Self {
globs: vec![Self::qualify_category(category, refspec::pattern!("*"))],
glob_type: PhantomData,
}
}
pub fn categories<R>(category: R, glob: PatternString) -> Self
where
R: AsRef<RefStr>,
{
let globs = vec![Self::qualify_category(category, glob)];
Self {
globs,
glob_type: PhantomData,
}
}
pub fn insert<R>(mut self, category: R, glob: PatternString) -> Self
where
R: AsRef<RefStr>,
{
self.globs.push(Self::qualify_category(category, glob));
self
}
fn qualify_category<R>(category: R, glob: PatternString) -> QualifiedPattern<'static>
where
R: AsRef<RefStr>,
{
let prefix = refname!("refs").and(category);
qualify(&prefix, glob).expect("BUG: pattern is qualified")
}
}
fn qualify(prefix: &RefString, glob: PatternString) -> Option<QualifiedPattern<'static>> {
prefix.to_pattern(glob).qualified().map(|q| q.into_owned())
}