diff options
Diffstat (limited to 'vendor/gix-index/src/init.rs')
-rw-r--r-- | vendor/gix-index/src/init.rs | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/vendor/gix-index/src/init.rs b/vendor/gix-index/src/init.rs new file mode 100644 index 000000000..abd71ffdd --- /dev/null +++ b/vendor/gix-index/src/init.rs @@ -0,0 +1,155 @@ +mod from_tree { + use std::collections::VecDeque; + + use bstr::{BStr, BString, ByteSlice, ByteVec}; + use gix_object::{ + tree::{self, EntryMode}, + TreeRefIter, + }; + use gix_traverse::tree::{breadthfirst, visit::Action, Visit}; + + use crate::{ + entry::{Flags, Mode, Stat}, + Entry, PathStorage, State, Version, + }; + + /// Initialization + impl State { + /// Return a new and empty in-memory index assuming the given `object_hash`. + pub fn new(object_hash: gix_hash::Kind) -> Self { + State { + object_hash, + timestamp: filetime::FileTime::now(), + version: Version::V2, + entries: vec![], + path_backing: vec![], + is_sparse: false, + tree: None, + link: None, + resolve_undo: None, + untracked: None, + fs_monitor: None, + } + } + /// Create an index [`State`][crate::State] by traversing `tree` recursively, accessing sub-trees + /// with `find`. + /// + /// **No extension data is currently produced**. + pub fn from_tree<Find>(tree: &gix_hash::oid, mut find: Find) -> Result<Self, breadthfirst::Error> + where + Find: for<'a> FnMut(&gix_hash::oid, &'a mut Vec<u8>) -> Option<TreeRefIter<'a>>, + { + let mut buf = Vec::new(); + let root = find(tree, &mut buf).ok_or(breadthfirst::Error::NotFound { oid: tree.into() })?; + + let mut delegate = CollectEntries::new(); + breadthfirst(root, breadthfirst::State::default(), &mut find, &mut delegate)?; + + let CollectEntries { + mut entries, + path_backing, + path: _, + path_deque: _, + } = delegate; + + entries.sort_by(|a, b| Entry::cmp_filepaths(a.path_in(&path_backing), b.path_in(&path_backing))); + + Ok(State { + object_hash: tree.kind(), + timestamp: filetime::FileTime::now(), + version: Version::V2, + entries, + path_backing, + is_sparse: false, + tree: None, + link: None, + resolve_undo: None, + untracked: None, + fs_monitor: None, + }) + } + } + + struct CollectEntries { + entries: Vec<Entry>, + path_backing: PathStorage, + path: BString, + path_deque: VecDeque<BString>, + } + + impl CollectEntries { + pub fn new() -> CollectEntries { + CollectEntries { + entries: Vec::new(), + path_backing: Vec::new(), + path: BString::default(), + path_deque: VecDeque::new(), + } + } + + fn push_element(&mut self, name: &BStr) { + if !self.path.is_empty() { + self.path.push(b'/'); + } + self.path.push_str(name); + } + + pub fn add_entry(&mut self, entry: &tree::EntryRef<'_>) { + let mode = match entry.mode { + EntryMode::Tree => unreachable!("visit_non_tree() called us"), + EntryMode::Blob => Mode::FILE, + EntryMode::BlobExecutable => Mode::FILE_EXECUTABLE, + EntryMode::Link => Mode::SYMLINK, + EntryMode::Commit => Mode::COMMIT, + }; + + let path_start = self.path_backing.len(); + self.path_backing.extend_from_slice(&self.path); + + let new_entry = Entry { + stat: Stat::default(), + id: entry.oid.into(), + flags: Flags::empty(), + mode, + path: path_start..self.path_backing.len(), + }; + + self.entries.push(new_entry); + } + } + + impl Visit for CollectEntries { + fn pop_front_tracked_path_and_set_current(&mut self) { + self.path = self + .path_deque + .pop_front() + .expect("every call is matched with push_tracked_path_component"); + } + + fn push_back_tracked_path_component(&mut self, component: &bstr::BStr) { + self.push_element(component); + self.path_deque.push_back(self.path.clone()); + } + + fn push_path_component(&mut self, component: &bstr::BStr) { + self.push_element(component); + } + + fn pop_path_component(&mut self) { + if let Some(pos) = self.path.rfind_byte(b'/') { + self.path.resize(pos, 0); + } else { + self.path.clear(); + } + } + + fn visit_tree(&mut self, _entry: &gix_object::tree::EntryRef<'_>) -> gix_traverse::tree::visit::Action { + Action::Continue + } + + fn visit_nontree(&mut self, entry: &gix_object::tree::EntryRef<'_>) -> gix_traverse::tree::visit::Action { + self.add_entry(entry); + Action::Continue + } + } +} |