ex-cli 1.21.0

Command line tool to find, filter, sort and list files.
Documentation
use crate::error::{MyError, MyResult};
use git2::Status;

#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct GitFlags {
    pub everything: bool,
    pub cached: bool,
    pub added: bool,
    pub modified: bool,
    pub renamed: bool,
    pub untracked: bool,
    pub ignored: bool,
}

impl GitFlags {
    pub fn from_str(value: &str) -> MyResult<Self> {
        let mut flags = Self::default();
        for ch in value.chars() {
            match ch {
                'x' => flags.everything = true,
                'c' => flags.cached = true,
                'a' => flags.added = true,
                'm' => flags.modified = true,
                'r' => flags.renamed = true,
                'u' => flags.untracked = true,
                'i' => flags.ignored = true,
                _ => return Err(MyError::create_clap("git", ch)),
            }
        }
        Ok(flags)
    }

    pub fn with_everything(mut self, everything: bool) -> Self {
        self.everything = everything;
        self
    }

    pub fn with_cached(mut self, cached: bool) -> Self {
        self.cached = cached;
        self
    }

    pub fn with_added(mut self, added: bool) -> Self {
        self.added = added;
        self
    }

    pub fn with_modified(mut self, modified: bool) -> Self {
        self.modified = modified;
        self
    }

    pub fn with_renamed(mut self, renamed: bool) -> Self {
        self.renamed = renamed;
        self
    }

    pub fn with_untracked(mut self, untracked: bool) -> Self {
        self.untracked = untracked;
        self
    }

    pub fn with_ignored(mut self, ignored: bool) -> Self {
        self.ignored = ignored;
        self
    }

    pub fn test_allowed(&self, status: &Status) -> Option<Self> {
        if self.is_allowed(status) {
            let flags = Self::default()
                .with_added(status.is_index_new())
                .with_modified(status.is_index_modified() || status.is_wt_modified())
                .with_renamed(status.is_index_renamed() || status.is_wt_renamed())
                .with_untracked(status.is_wt_new())
                .with_ignored(status.is_ignored());
            Some(flags)
        } else {
            None
        }
    }

    fn is_allowed(&self, status: &Status) -> bool {
        if self.everything {
            return true;
        }
        if self.cached && !status.is_ignored() && !status.is_wt_new() {
            return true;
        }
        if self.added && status.is_index_new() {
            return true;
        }
        if self.modified && (status.is_index_modified() || status.is_wt_modified()) {
            return true;
        }
        if self.renamed && (status.is_index_renamed() || status.is_wt_renamed()) {
            return true;
        }
        if self.untracked && status.is_wt_new() {
            return true;
        }
        if self.ignored && status.is_ignored() {
            return true;
        }
        false
    }
}

#[cfg(test)]
mod tests {
    use crate::git::flags::GitFlags;
    use git2::Status;

    #[test]
    fn test_files_are_included_with_cached_flag() {
        let flags = GitFlags::default().with_cached(true);
        assert_eq!(true, flags.is_allowed(&Status::INDEX_NEW));
        assert_eq!(true, flags.is_allowed(&Status::INDEX_MODIFIED));
        assert_eq!(true, flags.is_allowed(&Status::INDEX_RENAMED));
        assert_eq!(true, flags.is_allowed(&Status::INDEX_DELETED));
        assert_eq!(true, flags.is_allowed(&Status::INDEX_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_NEW));
        assert_eq!(true, flags.is_allowed(&Status::WT_MODIFIED));
        assert_eq!(true, flags.is_allowed(&Status::WT_RENAMED));
        assert_eq!(true, flags.is_allowed(&Status::WT_DELETED));
        assert_eq!(true, flags.is_allowed(&Status::WT_TYPECHANGE));
        assert_eq!(true, flags.is_allowed(&Status::WT_UNREADABLE));
        assert_eq!(false, flags.is_allowed(&Status::IGNORED));
        assert_eq!(true, flags.is_allowed(&Status::CONFLICTED));
    }

    #[test]
    fn test_files_are_included_with_added_flag() {
        let flags = GitFlags::default().with_added(true);
        assert_eq!(true, flags.is_allowed(&Status::INDEX_NEW));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_MODIFIED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_NEW));
        assert_eq!(false, flags.is_allowed(&Status::WT_MODIFIED));
        assert_eq!(false, flags.is_allowed(&Status::WT_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::WT_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::WT_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_UNREADABLE));
        assert_eq!(false, flags.is_allowed(&Status::IGNORED));
        assert_eq!(false, flags.is_allowed(&Status::CONFLICTED));
    }

    #[test]
    fn test_files_are_included_with_modified_flag() {
        let flags = GitFlags::default().with_modified(true);
        assert_eq!(false, flags.is_allowed(&Status::INDEX_NEW));
        assert_eq!(true, flags.is_allowed(&Status::INDEX_MODIFIED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_NEW));
        assert_eq!(true, flags.is_allowed(&Status::WT_MODIFIED));
        assert_eq!(false, flags.is_allowed(&Status::WT_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::WT_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::WT_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_UNREADABLE));
        assert_eq!(false, flags.is_allowed(&Status::IGNORED));
        assert_eq!(false, flags.is_allowed(&Status::CONFLICTED));
    }

    #[test]
    fn test_files_are_included_with_renamed_flag() {
        let flags = GitFlags::default().with_renamed(true);
        assert_eq!(false, flags.is_allowed(&Status::INDEX_NEW));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_MODIFIED));
        assert_eq!(true, flags.is_allowed(&Status::INDEX_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_NEW));
        assert_eq!(false, flags.is_allowed(&Status::WT_MODIFIED));
        assert_eq!(true, flags.is_allowed(&Status::WT_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::WT_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::WT_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_UNREADABLE));
        assert_eq!(false, flags.is_allowed(&Status::IGNORED));
        assert_eq!(false, flags.is_allowed(&Status::CONFLICTED));
    }

    #[test]
    fn test_files_are_included_with_untracked_flag() {
        let flags = GitFlags::default().with_untracked(true);
        assert_eq!(false, flags.is_allowed(&Status::INDEX_NEW));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_MODIFIED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_TYPECHANGE));
        assert_eq!(true, flags.is_allowed(&Status::WT_NEW));
        assert_eq!(false, flags.is_allowed(&Status::WT_MODIFIED));
        assert_eq!(false, flags.is_allowed(&Status::WT_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::WT_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::WT_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_UNREADABLE));
        assert_eq!(false, flags.is_allowed(&Status::IGNORED));
        assert_eq!(false, flags.is_allowed(&Status::CONFLICTED));
    }

    #[test]
    fn test_files_are_included_with_ignored_flag() {
        let flags = GitFlags::default().with_ignored(true);
        assert_eq!(false, flags.is_allowed(&Status::INDEX_NEW));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_MODIFIED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_NEW));
        assert_eq!(false, flags.is_allowed(&Status::WT_MODIFIED));
        assert_eq!(false, flags.is_allowed(&Status::WT_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::WT_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::WT_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_UNREADABLE));
        assert_eq!(true, flags.is_allowed(&Status::IGNORED));
        assert_eq!(false, flags.is_allowed(&Status::CONFLICTED));
    }

    #[test]
    fn test_files_are_included_with_multiple_flags() {
        let flags = GitFlags::default().with_added(true).with_modified(true).with_renamed(true);
        assert_eq!(true, flags.is_allowed(&Status::INDEX_NEW));
        assert_eq!(true, flags.is_allowed(&Status::INDEX_MODIFIED));
        assert_eq!(true, flags.is_allowed(&Status::INDEX_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::INDEX_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_NEW));
        assert_eq!(true, flags.is_allowed(&Status::WT_MODIFIED));
        assert_eq!(true, flags.is_allowed(&Status::WT_RENAMED));
        assert_eq!(false, flags.is_allowed(&Status::WT_DELETED));
        assert_eq!(false, flags.is_allowed(&Status::WT_TYPECHANGE));
        assert_eq!(false, flags.is_allowed(&Status::WT_UNREADABLE));
        assert_eq!(false, flags.is_allowed(&Status::IGNORED));
        assert_eq!(false, flags.is_allowed(&Status::CONFLICTED));
    }
}