147 lines · 4.7 KB · Rust
RawDownload
use std::path::{Path, PathBuf}; use bstr::{BStr, ByteSlice};use git_hash::oid; use super::Cache;use crate::{fs, fs::PathOidMapping}; #[derive(Clone)]pub enum State {    /// Useful for checkout where directories need creation, but we need to access attributes as well.    CreateDirectoryAndAttributesStack {        /// If there is a symlink or a file in our path, try to unlink it before creating the directory.        unlink_on_collision: bool,         /// just for testing        #[cfg(debug_assertions)]        test_mkdir_calls: usize,        /// State to handle attribute information        attributes: state::Attributes,    },    /// Used when adding files, requiring access to both attributes and ignore information, for example during add operations.    AttributesAndIgnoreStack {        /// State to handle attribute information        attributes: state::Attributes,        /// State to handle exclusion information        ignore: state::Ignore,    },    /// Used when providing worktree status information.    IgnoreStack(state::Ignore),} #[cfg(debug_assertions)]impl<'paths> Cache<'paths> {    pub fn set_case(&mut self, case: git_glob::pattern::Case) {        self.case = case;    }    pub fn num_mkdir_calls(&self) -> usize {        match self.state {            State::CreateDirectoryAndAttributesStack { test_mkdir_calls, .. } => test_mkdir_calls,            _ => 0,        }    }     pub fn reset_mkdir_calls(&mut self) {        if let State::CreateDirectoryAndAttributesStack { test_mkdir_calls, .. } = &mut self.state {            *test_mkdir_calls = 0;        }    }     pub fn unlink_on_collision(&mut self, value: bool) {        if let State::CreateDirectoryAndAttributesStack {            unlink_on_collision, ..        } = &mut self.state        {            *unlink_on_collision = value;        }    }} #[must_use]pub struct Platform<'a, 'paths> {    parent: &'a Cache<'paths>,    is_dir: Option<bool>,} impl<'paths> Cache<'paths> {    /// Create a new instance with `worktree_root` being the base for all future paths we handle, assuming it to be valid which includes    /// symbolic links to be included in it as well.    /// The `case` configures attribute and exclusion query case sensitivity.    pub fn new(        worktree_root: impl Into<PathBuf>,        state: State,        case: git_glob::pattern::Case,        buf: Vec<u8>,        attribute_files_in_index: Vec<PathOidMapping<'paths>>,    ) -> Self {        let root = worktree_root.into();        Cache {            stack: fs::Stack::new(root),            state,            case,            buf,            attribute_files_in_index,        }    }     /// Append the `relative` path to the root directory the cache contains and efficiently create leading directories    /// unless `is_dir` is known (`Some(…)`) then `relative` points to a directory itself in which case the entire resulting    /// path is created as directory. If it's not known it is assumed to be a file.    ///    /// Provide access to cached information for that `relative` entry via the platform returned.    pub fn at_path<Find, E>(        &mut self,        relative: impl AsRef<Path>,        is_dir: Option<bool>,        find: Find,    ) -> std::io::Result<Platform<'_, 'paths>>    where        Find: for<'a> FnMut(&oid, &'a mut Vec<u8>) -> Result<git_object::BlobRef<'a>, E>,        E: std::error::Error + Send + Sync + 'static,    {        let mut delegate = platform::StackDelegate {            state: &mut self.state,            buf: &mut self.buf,            is_dir: is_dir.unwrap_or(false),            attribute_files_in_index: &self.attribute_files_in_index,            find,        };        self.stack.make_relative_path_current(relative, &mut delegate)?;        Ok(Platform { parent: self, is_dir })    }     /// **Panics** on illformed UTF8 in `relative`    // TODO: more docs    pub fn at_entry<'r, Find, E>(        &mut self,        relative: impl Into<&'r BStr>,        is_dir: Option<bool>,        find: Find,    ) -> std::io::Result<Platform<'_, 'paths>>    where        Find: for<'a> FnMut(&oid, &'a mut Vec<u8>) -> Result<git_object::BlobRef<'a>, E>,        E: std::error::Error + Send + Sync + 'static,    {        let relative = relative.into();        let relative_path = git_path::from_bstr(relative);         self.at_path(            relative_path,            is_dir.or_else(|| relative.ends_with_str("/").then(|| true)),            // is_dir,            find,        )    }     /// Return the base path against which all entries or paths should be relative to when querying.    ///    /// Note that this path _may_ not be canonicalized.    pub fn base(&self) -> &Path {        self.stack.root()    }} mod platform;///pub mod state;