Files
radicle-git/radicle-git-ext/src/tree.rs
T
Fintan Halpenny b570fa1435 Re-License to "MIT OR Aapache-2.0"
The main dependant of `radicle-git`, and its crates, is [`heartwood`].
It is licensed under MIT or Apache-2.0, which has been incompatible with the GPL-3.0 license.
Since the intellectual property of this code base is with the Better Internet Foundation, it was
decided to re-license code in this repository to make the upstream repository compatible.

 - Remove the license headers (and instructions to add them)
 - Add MIT and Apache-2.0 licenses
 - Remove the GPL-3.0 license
 - Change the license declarations in the `Cargo.toml` files

[`heartwood`]: https://app.radicle.xyz/nodes/seed.radicle.xyz/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
2025-11-14 12:52:22 +01:00

143 lines
3.5 KiB
Rust

use std::{borrow::Cow, collections::BTreeMap, iter::FromIterator};
/// A simplified representation of a git tree, intended mainly to be created
/// from literals.
///
/// # Example
///
/// ```
/// use radicle_git_ext::tree::{Tree, blob};
///
/// let my_tree = vec![
/// ("README", blob(b"awe")),
/// ("src", vec![("main.rs", blob(b"fn main() {}"))].into_iter().collect()),
/// ]
/// .into_iter()
/// .collect::<Tree>();
///
/// assert_eq!(
/// format!("{:?}", my_tree),
/// "Tree(\
/// {\
/// \"README\": Blob(\
/// [\
/// 97, \
/// 119, \
/// 101\
/// ]\
/// ), \
/// \"src\": Tree(\
/// Tree(\
/// {\
/// \"main.rs\": Blob(\
/// [\
/// 102, \
/// 110, \
/// 32, \
/// 109, \
/// 97, \
/// 105, \
/// 110, \
/// 40, \
/// 41, \
/// 32, \
/// 123, \
/// 125\
/// ]\
/// )\
/// }\
/// )\
/// )\
/// }\
/// )"
/// )
/// ```
#[derive(Clone, Debug)]
pub struct Tree<'a>(BTreeMap<Cow<'a, str>, Node<'a>>);
impl Tree<'_> {
pub fn write(&self, repo: &git2::Repository) -> Result<git2::Oid, git2::Error> {
use Node::*;
let mut builder = repo.treebuilder(None)?;
for (name, node) in &self.0 {
match node {
Blob(data) => {
let oid = repo.blob(data)?;
builder.insert(name.as_ref(), oid, git2::FileMode::Blob.into())?;
}
Tree(sub) => {
let oid = sub.write(repo)?;
builder.insert(name.as_ref(), oid, git2::FileMode::Tree.into())?;
}
}
}
builder.write()
}
}
impl<'a> From<BTreeMap<Cow<'a, str>, Node<'a>>> for Tree<'a> {
fn from(map: BTreeMap<Cow<'a, str>, Node<'a>>) -> Self {
Self(map)
}
}
impl<'a, K, N> FromIterator<(K, N)> for Tree<'a>
where
K: Into<Cow<'a, str>>,
N: Into<Node<'a>>,
{
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = (K, N)>,
{
Self(
iter.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect(),
)
}
}
#[derive(Clone, Debug)]
pub enum Node<'a> {
Blob(Cow<'a, [u8]>),
Tree(Tree<'a>),
}
pub fn blob(slice: &[u8]) -> Node {
Node::from(slice)
}
impl<'a> From<&'a [u8]> for Node<'a> {
fn from(slice: &'a [u8]) -> Self {
Self::from(Cow::Borrowed(slice))
}
}
impl<'a> From<Cow<'a, [u8]>> for Node<'a> {
fn from(bytes: Cow<'a, [u8]>) -> Self {
Self::Blob(bytes)
}
}
impl<'a> From<Tree<'a>> for Node<'a> {
fn from(tree: Tree<'a>) -> Self {
Self::Tree(tree)
}
}
impl<'a, K, N> FromIterator<(K, N)> for Node<'a>
where
K: Into<Cow<'a, str>>,
N: Into<Node<'a>>,
{
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = (K, N)>,
{
Self::Tree(iter.into_iter().collect())
}
}