139 lines · 5.5 KB · Rust
RawDownload
use crate::entry::Mode; impl Mode {    /// Return `true` if this is a sparse entry, as it points to a directory which usually isn't what an 'unsparse' index tracks.    pub fn is_sparse(&self) -> bool {        *self == Self::DIR    }     /// Return `true` if this is a submodule entry.    pub fn is_submodule(&self) -> bool {        *self == Self::DIR | Self::SYMLINK    }     /// Convert this instance to a tree's entry mode, or return `None` if for some    /// and unexpected reason the bitflags don't resemble any known entry-mode.    pub fn to_tree_entry_mode(&self) -> Option<gix_object::tree::EntryMode> {        gix_object::tree::EntryMode::try_from(self.bits()).ok()    }     /// Compares this mode to the file system version ([`std::fs::symlink_metadata`])    /// and returns the change needed to update this mode to match the file.    ///    /// * if `has_symlinks` is false symlink entries will simply check if there    ///   is a normal file on disk    /// * if `executable_bit` is false the executable bit will not be compared    ///   `Change::ExecutableBit` will never be generated    ///    /// If there is a type change then we will use whatever information is    /// present on the FS. Specifically if `has_symlinks` is false we will    /// never generate `Change::TypeChange { new_mode: Mode::SYMLINK }`. and    /// if `executable_bit` is false we will never generate `Change::TypeChange    /// { new_mode: Mode::FILE_EXECUTABLE }` (all files are assumed to be not    /// executable). That means that unstaging and staging files can be a lossy    /// operation on such file systems.    ///    /// If a directory replaced a normal file/symlink we assume that the    /// directory is a submodule. Normal (non-submodule) directories would    /// cause a file to be deleted from the index and should be handled before    /// calling this function.    ///    /// If the stat information belongs to something other than a normal file/    /// directory (like a socket) we just return an identity change (non-files    /// can not be committed to git).    pub fn change_to_match_fs(        self,        stat: &crate::fs::Metadata,        has_symlinks: bool,        executable_bit: bool,    ) -> Option<Change> {        self.change_to_match_fs_with_values(            stat.is_file(),            stat.is_dir(),            stat.is_symlink(),            stat.is_executable(),            has_symlinks,            executable_bit,        )    }     /// Like [`change_to_match_fs`](Self::change_to_match_fs) but accepts pre-extracted    /// file-type and permission bits, for callers that already have them (e.g. cached    /// metadata from a batched directory enumeration).    ///    /// Note that some parameters are mutually exclusive, but inconsistency won't be a problem    /// if the source of the data is consistent.    ///    /// * `is_file` is `true` if the file-system entry is a regular file.    /// * `is_dir` is `true` if the file-system entry is a directory.    /// * `is_symlink` is `true` if the file-system entry is a symbolic link.    /// * `is_executable` is `true` if the file-system entry has executable permissions.    ///    /// These parameters match [`change_to_match_fs`](Self::change_to_match_fs).    ///    /// * `has_symlinks` is `true` if the file system represents symbolic links faithfully.    /// * `executable_bit` is `true` if the file system represents executable permissions faithfully.    pub fn change_to_match_fs_with_values(        self,        is_file: bool,        is_dir: bool,        is_symlink: bool,        is_executable: bool,        has_symlinks: bool,        executable_bit: bool,    ) -> Option<Change> {        match self {            Mode::FILE if !is_file => (),            Mode::SYMLINK if is_symlink => return None,            Mode::SYMLINK if has_symlinks && !is_symlink => (),            Mode::SYMLINK if !has_symlinks && !is_file => (),            Mode::COMMIT | Mode::DIR if !is_dir => (),            Mode::FILE if executable_bit && is_executable => return Some(Change::ExecutableBit),            Mode::FILE_EXECUTABLE if executable_bit && !is_executable => return Some(Change::ExecutableBit),            _ => return None,        }        let new_mode = if is_dir {            Mode::COMMIT        } else if executable_bit && is_executable {            Mode::FILE_EXECUTABLE        } else if has_symlinks && is_symlink {            Mode::SYMLINK        } else {            Mode::FILE        };        Some(Change::Type { new_mode })    }} impl From<gix_object::tree::EntryMode> for Mode {    fn from(value: gix_object::tree::EntryMode) -> Self {        let value: u16 = value.value();        Self::from_bits_truncate(u32::from(value))    }} /// A change of a [`Mode`].#[derive(Debug, Copy, Clone, PartialEq, Eq)]pub enum Change {    /// The type of mode changed, like symlink => file.    Type {        /// The mode representing the new index type.        new_mode: Mode,    },    /// The executable permission of this file has changed.    ExecutableBit,} impl Change {    /// Applies this change to `mode` and returns the changed one.    pub fn apply(self, mode: Mode) -> Mode {        match self {            Change::Type { new_mode } => new_mode,            Change::ExecutableBit => match mode {                Mode::FILE => Mode::FILE_EXECUTABLE,                Mode::FILE_EXECUTABLE => Mode::FILE,                _ => unreachable!("invalid mode change: can't flip executable bit of {mode:?}"),            },        }    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t