Radish alpha
r
rad:z6cFWeWpnZNHh9rUW8phgA3b5yGt
Git libraries for Radicle
Radicle
Git
radicle-git radicle-git-ext t src gen commit.rs
use std::convert::Infallible;

use proptest::strategy::Strategy;
use radicle_git_ext::commit::{self, CommitData};

mod author;
mod headers;
mod trailers;

pub use author::author;
pub use headers::headers;
pub use trailers::{trailer, trailers};

use super::alphanumeric;

pub fn commit() -> impl Strategy<Value = CommitData<TreeData, Infallible>> {
    (
        TreeData::gen(),
        author(),
        author(),
        headers(),
        alphanumeric(),
        trailers(3),
    )
        .prop_map(|(tree, author, committer, headers, message, trailers)| {
            CommitData::new(tree, vec![], author, committer, headers, message, trailers)
        })
}

pub fn write_commits(
    repo: &git2::Repository,
    linear: Vec<CommitData<TreeData, Infallible>>,
) -> Result<Vec<git2::Oid>, commit::error::Write> {
    let mut parent = None;
    let mut commits = Vec::new();
    for commit in linear {
        let commit = commit.map_tree(|tree| tree.write(repo))?;
        let commit = match parent {
            Some(parent) => commit
                .map_parents::<git2::Oid, Infallible, _>(|_| Ok(parent))
                .unwrap(),
            None => commit
                .map_parents::<git2::Oid, Infallible, _>(|_| unreachable!("no parents"))
                .unwrap(),
        };
        let oid = commit.write(repo)?;
        commits.push(oid);
        parent = Some(oid);
    }
    Ok(commits)
}

#[derive(Clone, Debug)]
pub enum TreeData {
    Blob { name: String, data: String },
    Tree { name: String, inner: Vec<TreeData> },
}

impl TreeData {
    fn gen() -> impl Strategy<Value = Self> {
        let leaf =
            (alphanumeric(), alphanumeric()).prop_map(|(name, data)| Self::Blob { name, data });
        leaf.prop_recursive(8, 16, 5, |inner| {
            (proptest::collection::vec(inner, 1..5), alphanumeric())
                .prop_map(|(inner, name)| Self::Tree { name, inner })
        })
    }

    fn write(&self, repo: &git2::Repository) -> Result<git2::Oid, git2::Error> {
        let mut builder = repo.treebuilder(None)?;
        self.write_(repo, &mut builder)?;
        builder.write()
    }

    fn write_(
        &self,
        repo: &git2::Repository,
        builder: &mut git2::TreeBuilder,
    ) -> Result<git2::Oid, git2::Error> {
        match self {
            Self::Blob { name, data } => {
                let oid = repo.blob(data.as_bytes())?;
                builder.insert(name, oid, git2::FileMode::Blob.into())?;
            }
            Self::Tree { name, inner } => {
                for data in inner {
                    let oid = data.write_(repo, builder)?;
                    builder.insert(name, oid, git2::FileMode::Tree.into())?;
                }
            }
        }
        builder.write()
    }
}