160 lines · 5.5 KB · Rust
RawDownload
use std::path::PathBuf; pub use git_worktree::*; use crate::{    bstr::{BStr, BString},    Repository,}; pub(crate) type IndexStorage = git_features::threading::OwnShared<git_features::fs::MutableSnapshot<git_index::File>>;/// A lazily loaded and auto-updated worktree index.pub type Index = git_features::fs::SharedSnapshot<git_index::File>; /// A stand-in to a worktree as result of a worktree iteration.////// It provides access to typical worktree state, but may not actually point to a valid checkout as the latter has been moved or/// deleted.#[derive(Debug, Clone)]pub struct Proxy<'repo> {    pub(crate) parent: &'repo Repository,    pub(crate) git_dir: PathBuf,} /// Accessimpl<'repo> crate::Worktree<'repo> {    /// Read the location of the checkout, the base of the work tree    pub fn base(&self) -> &'repo std::path::Path {        self.path    }     /// Return true if this worktree is the main worktree associated with a non-bare git repository.    ///    /// It cannot be removed.    pub fn is_main(&self) -> bool {        self.id().is_none()    }     /// Return true if this worktree cannot be pruned, moved or deleted, which is useful if it is located on an external storage device.    ///    /// Always false for the main worktree.    pub fn is_locked(&self) -> bool {        Proxy::new(self.parent, self.parent.git_dir()).is_locked()    }     /// Provide a reason for the locking of this worktree, if it is locked at all.    ///    /// Note that we squelch errors in case the file cannot be read in which case the    /// reason is an empty string.    pub fn lock_reason(&self) -> Option<BString> {        Proxy::new(self.parent, self.parent.git_dir()).lock_reason()    }     /// Return the ID of the repository worktree, if it is a linked worktree, or `None` if it's a linked worktree.    pub fn id(&self) -> Option<&BStr> {        id(self.parent.git_dir(), self.parent.common_dir.is_some())    }} pub(crate) fn id(git_dir: &std::path::Path, has_common_dir: bool) -> Option<&BStr> {    if !has_common_dir {        return None;    }    let candidate = git_path::os_str_into_bstr(git_dir.file_name().expect("at least one directory level"))        .expect("no illformed UTF-8");    let maybe_worktrees = git_dir.parent()?;    (maybe_worktrees.file_name()?.to_str()? == "worktrees").then(|| candidate)} ///pub mod proxy; ///pub mod open_index {    use crate::bstr::BString;     /// The error returned by [`Worktree::open_index()`][crate::Worktree::open_index()].    #[derive(Debug, thiserror::Error)]    #[allow(missing_docs)]    pub enum Error {        #[error("Could not interpret value '{}' as 'index.threads'", .value)]        ConfigIndexThreads {            value: BString,            #[source]            err: git_config::value::Error,        },        #[error(transparent)]        IndexFile(#[from] git_index::file::init::Error),    }     impl<'repo> crate::Worktree<'repo> {        /// A shortcut to [`crate::Repository::open_index()`].        pub fn open_index(&self) -> Result<git_index::File, Error> {            self.parent.open_index()        }         /// A shortcut to [`crate::Repository::index()`].        pub fn index(&self) -> Result<crate::worktree::Index, Error> {            self.parent.index()        }    }} ///pub mod excludes {    use std::path::PathBuf;     /// The error returned by [`Worktree::excludes()`][crate::Worktree::excludes()].    #[derive(Debug, thiserror::Error)]    #[allow(missing_docs)]    pub enum Error {        #[error("Could not read repository exclude.")]        Io(#[from] std::io::Error),        #[error(transparent)]        EnvironmentPermission(#[from] git_sec::permission::Error<PathBuf>),        #[error("The value for `core.excludesFile` could not be read from configuration")]        ExcludesFilePathInterpolation(#[from] git_config::path::interpolate::Error),    }     impl<'repo> crate::Worktree<'repo> {        /// Configure a file-system cache checking if files below the repository are excluded.        ///        /// This takes into consideration all the usual repository configuration.        // TODO: test        pub fn excludes<'a>(            &self,            index: &'a git_index::State,            overrides: Option<git_attributes::MatchGroup<git_attributes::Ignore>>,        ) -> Result<git_worktree::fs::Cache<'a>, Error> {            let repo = self.parent;            let case = repo                .config                .ignore_case                .then(|| git_glob::pattern::Case::Fold)                .unwrap_or_default();            let mut buf = Vec::with_capacity(512);            let excludes_file = match repo.config.excludes_file().transpose()? {                Some(user_path) => Some(user_path),                None => repo.config.xdg_config_path("ignore")?,            };            let state = git_worktree::fs::cache::State::IgnoreStack(git_worktree::fs::cache::state::Ignore::new(                overrides.unwrap_or_default(),                git_attributes::MatchGroup::<git_attributes::Ignore>::from_git_dir(                    repo.git_dir(),                    excludes_file,                    &mut buf,                )?,                None,                case,            ));            let attribute_list = state.build_attribute_list(index, index.path_backing(), case);            Ok(git_worktree::fs::Cache::new(                self.path,                state,                case,                buf,                attribute_list,            ))        }    }}