Struct git_repository::Tree
source · Expand description
A decoded tree object with access to its owning repository.
Fields§
§id: ObjectId
The id of the tree
data: Vec<u8>
The fully decoded tree data
Implementations§
source§impl<'repo> Tree<'repo>
impl<'repo> Tree<'repo>
Diffing
sourcepub fn changes<'a>(&'a self) -> Platform<'a, 'repo>
pub fn changes<'a>(&'a self) -> Platform<'a, 'repo>
Return a platform to see the changes needed to create other trees, for instance.
Performance
It’s highly recommended to set an object cache to avoid extracting the same object multiple times.
source§impl<'repo> Tree<'repo>
impl<'repo> Tree<'repo>
Access
sourcepub fn lookup_entry<I, P>(self, path: I) -> Result<Option<Entry<'repo>>, Error>where
I: IntoIterator<Item = P>,
P: PartialEq<BStr>,
pub fn lookup_entry<I, P>(self, path: I) -> Result<Option<Entry<'repo>>, Error>where
I: IntoIterator<Item = P>,
P: PartialEq<BStr>,
Follow a sequence of path
components starting from this instance, and look them up one by one until the last component
is looked up and its tree entry is returned.
Performance Notes
Searching tree entries is currently done in sequence, which allows to the search to be allocation free. It would be possible to re-use a vector and use a binary search instead, which might be able to improve performance over all. However, a benchmark should be created first to have some data and see which trade-off to choose here.
Why is this consunming?
The borrow checker shows pathological behaviour in loops that mutate a buffer, but also want to return from it. Workarounds include keeping an index and doing a separate access to the memory, which seems hard to do here without re-parsing the entries.
Examples found in repository?
More examples
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
pub fn open_mailmap_into(&self, target: &mut git_mailmap::Snapshot) -> Result<(), crate::mailmap::load::Error> {
let mut err = None::<crate::mailmap::load::Error>;
let mut buf = Vec::new();
let mut blob_id = self
.config
.resolved
.raw_value("mailmap", None, "blob")
.ok()
.and_then(|spec| {
// TODO: actually resolve this as spec (once we can do that)
git_hash::ObjectId::from_hex(spec.as_ref())
.map_err(|e| err.get_or_insert(e.into()))
.ok()
});
match self.work_dir() {
None => {
// TODO: replace with ref-spec `HEAD:.mailmap` for less verbose way of getting the blob id
blob_id = blob_id.or_else(|| {
self.head().ok().and_then(|mut head| {
let commit = head.peel_to_commit_in_place().ok()?;
let tree = commit.tree().ok()?;
tree.lookup_entry(Some(".mailmap")).ok()?.map(|e| e.object_id())
})
});
}
Some(root) => {
if let Ok(mut file) = git_features::fs::open_options_no_follow()
.read(true)
.open(root.join(".mailmap"))
.map_err(|e| {
if e.kind() != std::io::ErrorKind::NotFound {
err.get_or_insert(e.into());
}
})
{
buf.clear();
std::io::copy(&mut file, &mut buf)
.map_err(|e| err.get_or_insert(e.into()))
.ok();
target.merge(git_mailmap::parse_ignore_errors(&buf));
}
}
}
if let Some(blob) = blob_id.and_then(|id| self.find_object(id).map_err(|e| err.get_or_insert(e.into())).ok()) {
target.merge(git_mailmap::parse_ignore_errors(&blob.data));
}
let configured_path = self
.config
.resolved
.value::<git_config::Path<'_>>("mailmap", None, "file")
.ok()
.and_then(|path| {
let install_dir = self.install_dir().ok()?;
let home = self.config.home_dir();
match path.interpolate(git_config::path::interpolate::Context {
git_install_dir: Some(install_dir.as_path()),
home_dir: home.as_deref(),
home_for_user: if self.options.git_dir_trust.expect("trust is set") == git_sec::Trust::Full {
Some(git_config::path::interpolate::home_for_user)
} else {
None
},
}) {
Ok(path) => Some(path),
Err(e) => {
err.get_or_insert(e.into());
None
}
}
});
if let Some(mut file) =
configured_path.and_then(|path| std::fs::File::open(path).map_err(|e| err.get_or_insert(e.into())).ok())
{
buf.clear();
std::io::copy(&mut file, &mut buf)
.map_err(|e| err.get_or_insert(e.into()))
.ok();
target.merge(git_mailmap::parse_ignore_errors(&buf));
}
err.map(Err).unwrap_or(Ok(()))
}
sourcepub fn lookup_entry_by_path(
self,
relative_path: impl AsRef<Path>
) -> Result<Option<Entry<'repo>>, Error>
pub fn lookup_entry_by_path(
self,
relative_path: impl AsRef<Path>
) -> Result<Option<Entry<'repo>>, Error>
Like lookup_entry()
, but takes a Path
directly via relative_path
, a path relative to this tree.
Note
If any path component contains illformed UTF-8 and thus can’t be converted to bytes on platforms which can’t do so natively, the returned component will be empty which makes the lookup fail.
Examples found in repository?
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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
fn peel_until(&mut self, kind: PeelTo<'_>) -> Option<()> {
self.unset_disambiguate_call();
self.follow_refs_to_objects_if_needed()?;
let mut replacements = Replacements::default();
let mut errors = Vec::new();
let objs = self.objs[self.idx].as_mut()?;
let repo = self.repo;
match kind {
PeelTo::ValidObject => {
for obj in objs.iter() {
match repo.find_object(*obj) {
Ok(_) => {}
Err(err) => {
errors.push((*obj, err.into()));
}
};
}
}
PeelTo::ObjectKind(kind) => {
let peel = |obj| peel(repo, obj, kind);
for obj in objs.iter() {
match peel(obj) {
Ok(replace) => replacements.push((*obj, replace)),
Err(err) => errors.push((*obj, err)),
}
}
}
PeelTo::Path(path) => {
let lookup_path = |obj: &ObjectId| {
let tree_id = peel(repo, obj, git_object::Kind::Tree)?;
if path.is_empty() {
return Ok(tree_id);
}
let tree = repo.find_object(tree_id)?.into_tree();
let entry =
tree.lookup_entry_by_path(git_path::from_bstr(path))?
.ok_or_else(|| Error::PathNotFound {
path: path.into(),
object: obj.attach(repo).shorten_or_id(),
tree: tree_id.attach(repo).shorten_or_id(),
})?;
Ok(entry.object_id())
};
for obj in objs.iter() {
match lookup_path(obj) {
Ok(replace) => replacements.push((*obj, replace)),
Err(err) => errors.push((*obj, err)),
}
}
}
PeelTo::RecursiveTagObject => {
for oid in objs.iter() {
match oid.attach(repo).object().and_then(|obj| obj.peel_tags_to_end()) {
Ok(obj) => replacements.push((*oid, obj.id)),
Err(err) => errors.push((*oid, err.into())),
}
}
}
}
handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
}