1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
use std::cmp::Ordering;
use crate::{
bstr::{BStr, BString},
tree,
};
mod ref_iter;
///
pub mod write;
/// The mode of items storable in a tree, similar to the file mode on a unix file system.
///
/// Used in [mutable::Entry][crate::tree::Entry] and [EntryRef].
#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash)]
#[repr(u16)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum EntryMode {
/// A tree, or directory
Tree = 0o040000u16,
/// A file that is not executable
Blob = 0o100644,
/// A file that is executable
BlobExecutable = 0o100755,
/// A symbolic link
Link = 0o120000,
/// A commit of a git submodule
Commit = 0o160000,
}
impl EntryMode {
/// Return true if this entry mode represents a Tree/directory
pub fn is_tree(&self) -> bool {
*self == EntryMode::Tree
}
/// Return true if this entry mode represents anything BUT Tree/directory
pub fn is_no_tree(&self) -> bool {
*self != EntryMode::Tree
}
/// Return true if the entry is any kind of blob.
pub fn is_blob(&self) -> bool {
matches!(self, EntryMode::Blob | EntryMode::BlobExecutable)
}
/// Return true if the entry is any kind of blob or symlink.
pub fn is_blob_or_symlink(&self) -> bool {
matches!(self, EntryMode::Blob | EntryMode::BlobExecutable | EntryMode::Link)
}
/// Represent the mode as descriptive string.
pub fn as_str(&self) -> &'static str {
use EntryMode::*;
match self {
Tree => "tree",
Blob => "blob",
BlobExecutable => "exe",
Link => "link",
Commit => "commit",
}
}
}
/// An element of a [`TreeRef`][crate::TreeRef::entries].
#[derive(PartialEq, Eq, Debug, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EntryRef<'a> {
/// The kind of object to which `oid` is pointing.
pub mode: tree::EntryMode,
/// The name of the file in the parent tree.
pub filename: &'a BStr,
/// The id of the object representing the entry.
// TODO: figure out how these should be called. id or oid? It's inconsistent around the codebase.
// Answer: make it 'id', as in `git2`
#[cfg_attr(feature = "serde", serde(borrow))]
pub oid: &'a gix_hash::oid,
}
impl<'a> PartialOrd for EntryRef<'a> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a> Ord for EntryRef<'a> {
/// Entries compare by the common portion of the filename. This is critical for proper functioning of algorithms working on trees.
/// Doing it like this is needed for compatibility with older, potentially broken(?) trees.
fn cmp(&self, other: &Self) -> Ordering {
let len = self.filename.len().min(other.filename.len());
self.filename[..len].cmp(&other.filename[..len])
}
}
/// An entry in a [`Tree`][crate::Tree], similar to an entry in a directory.
#[derive(PartialEq, Eq, Debug, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Entry {
/// The kind of object to which `oid` is pointing to.
pub mode: EntryMode,
/// The name of the file in the parent tree.
pub filename: BString,
/// The id of the object representing the entry.
pub oid: gix_hash::ObjectId,
}
impl PartialOrd for Entry {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Entry {
/// Entries compare by the common portion of the filename. This is critical for proper functioning of algorithms working on trees.
fn cmp(&self, other: &Self) -> Ordering {
let common_len = self.filename.len().min(other.filename.len());
self.filename[..common_len]
.cmp(&other.filename[..common_len])
.then_with(|| self.filename.len().cmp(&other.filename.len()))
}
}
/// Serialization
impl EntryMode {
/// Return the representation as used in the git internal format.
pub fn as_bytes(&self) -> &'static [u8] {
use EntryMode::*;
match self {
Tree => b"40000",
Blob => b"100644",
BlobExecutable => b"100755",
Link => b"120000",
Commit => b"160000",
}
}
}