Skip to main content

ex_cli/git/
flags.rs

1use crate::error::{MyError, MyResult};
2use git2::Status;
3
4#[derive(Clone, Copy, Debug, Default, PartialEq)]
5pub struct GitFlags {
6    pub everything: bool,
7    pub cached: bool,
8    pub added: bool,
9    pub modified: bool,
10    pub renamed: bool,
11    pub untracked: bool,
12    pub ignored: bool,
13}
14
15impl GitFlags {
16    pub fn from_str(value: &str) -> MyResult<Self> {
17        let mut flags = Self::default();
18        for ch in value.chars() {
19            match ch {
20                'x' => flags.everything = true,
21                'c' => flags.cached = true,
22                'a' => flags.added = true,
23                'm' => flags.modified = true,
24                'r' => flags.renamed = true,
25                'u' => flags.untracked = true,
26                'i' => flags.ignored = true,
27                _ => return Err(MyError::create_clap("git", ch)),
28            }
29        }
30        Ok(flags)
31    }
32
33    pub fn with_everything(mut self, everything: bool) -> Self {
34        self.everything = everything;
35        self
36    }
37
38    pub fn with_cached(mut self, cached: bool) -> Self {
39        self.cached = cached;
40        self
41    }
42
43    pub fn with_added(mut self, added: bool) -> Self {
44        self.added = added;
45        self
46    }
47
48    pub fn with_modified(mut self, modified: bool) -> Self {
49        self.modified = modified;
50        self
51    }
52
53    pub fn with_renamed(mut self, renamed: bool) -> Self {
54        self.renamed = renamed;
55        self
56    }
57
58    pub fn with_untracked(mut self, untracked: bool) -> Self {
59        self.untracked = untracked;
60        self
61    }
62
63    pub fn with_ignored(mut self, ignored: bool) -> Self {
64        self.ignored = ignored;
65        self
66    }
67
68    pub fn test_allowed(&self, status: Status) -> Option<Self> {
69        if self.is_allowed(status) {
70            let flags = Self::default()
71                .with_added(status.is_index_new())
72                .with_modified(status.is_index_modified() || status.is_wt_modified())
73                .with_renamed(status.is_index_renamed() || status.is_wt_renamed())
74                .with_untracked(status.is_wt_new())
75                .with_ignored(status.is_ignored());
76            Some(flags)
77        } else {
78            None
79        }
80    }
81
82    fn is_allowed(&self, status: Status) -> bool {
83        if self.everything {
84            return true;
85        }
86        if self.cached && !status.is_ignored() && !status.is_wt_new() {
87            return true;
88        }
89        if self.added && status.is_index_new() {
90            return true;
91        }
92        if self.modified && (status.is_index_modified() || status.is_wt_modified()) {
93            return true;
94        }
95        if self.renamed && (status.is_index_renamed() || status.is_wt_renamed()) {
96            return true;
97        }
98        if self.untracked && status.is_wt_new() {
99            return true;
100        }
101        if self.ignored && status.is_ignored() {
102            return true;
103        }
104        false
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use crate::git::flags::GitFlags;
111    use git2::Status;
112    use googletest::prelude::*;
113
114    #[gtest]
115    fn test_files_are_included_with_cached_flag() {
116        let flags = GitFlags::default().with_cached(true);
117        expect_true!(flags.is_allowed(Status::INDEX_NEW));
118        expect_true!(flags.is_allowed(Status::INDEX_MODIFIED));
119        expect_true!(flags.is_allowed(Status::INDEX_RENAMED));
120        expect_true!(flags.is_allowed(Status::INDEX_DELETED));
121        expect_true!(flags.is_allowed(Status::INDEX_TYPECHANGE));
122        expect_false!(flags.is_allowed(Status::WT_NEW));
123        expect_true!(flags.is_allowed(Status::WT_MODIFIED));
124        expect_true!(flags.is_allowed(Status::WT_RENAMED));
125        expect_true!(flags.is_allowed(Status::WT_DELETED));
126        expect_true!(flags.is_allowed(Status::WT_TYPECHANGE));
127        expect_true!(flags.is_allowed(Status::WT_UNREADABLE));
128        expect_false!(flags.is_allowed(Status::IGNORED));
129        expect_true!(flags.is_allowed(Status::CONFLICTED));
130    }
131
132    #[gtest]
133    fn test_files_are_included_with_added_flag() {
134        let flags = GitFlags::default().with_added(true);
135        expect_true!(flags.is_allowed(Status::INDEX_NEW));
136        expect_false!(flags.is_allowed(Status::INDEX_MODIFIED));
137        expect_false!(flags.is_allowed(Status::INDEX_RENAMED));
138        expect_false!(flags.is_allowed(Status::INDEX_DELETED));
139        expect_false!(flags.is_allowed(Status::INDEX_TYPECHANGE));
140        expect_false!(flags.is_allowed(Status::WT_NEW));
141        expect_false!(flags.is_allowed(Status::WT_MODIFIED));
142        expect_false!(flags.is_allowed(Status::WT_RENAMED));
143        expect_false!(flags.is_allowed(Status::WT_DELETED));
144        expect_false!(flags.is_allowed(Status::WT_TYPECHANGE));
145        expect_false!(flags.is_allowed(Status::WT_UNREADABLE));
146        expect_false!(flags.is_allowed(Status::IGNORED));
147        expect_false!(flags.is_allowed(Status::CONFLICTED));
148    }
149
150    #[gtest]
151    fn test_files_are_included_with_modified_flag() {
152        let flags = GitFlags::default().with_modified(true);
153        expect_false!(flags.is_allowed(Status::INDEX_NEW));
154        expect_true!(flags.is_allowed(Status::INDEX_MODIFIED));
155        expect_false!(flags.is_allowed(Status::INDEX_RENAMED));
156        expect_false!(flags.is_allowed(Status::INDEX_DELETED));
157        expect_false!(flags.is_allowed(Status::INDEX_TYPECHANGE));
158        expect_false!(flags.is_allowed(Status::WT_NEW));
159        expect_true!(flags.is_allowed(Status::WT_MODIFIED));
160        expect_false!(flags.is_allowed(Status::WT_RENAMED));
161        expect_false!(flags.is_allowed(Status::WT_DELETED));
162        expect_false!(flags.is_allowed(Status::WT_TYPECHANGE));
163        expect_false!(flags.is_allowed(Status::WT_UNREADABLE));
164        expect_false!(flags.is_allowed(Status::IGNORED));
165        expect_false!(flags.is_allowed(Status::CONFLICTED));
166    }
167
168    #[gtest]
169    fn test_files_are_included_with_renamed_flag() {
170        let flags = GitFlags::default().with_renamed(true);
171        expect_false!(flags.is_allowed(Status::INDEX_NEW));
172        expect_false!(flags.is_allowed(Status::INDEX_MODIFIED));
173        expect_true!(flags.is_allowed(Status::INDEX_RENAMED));
174        expect_false!(flags.is_allowed(Status::INDEX_DELETED));
175        expect_false!(flags.is_allowed(Status::INDEX_TYPECHANGE));
176        expect_false!(flags.is_allowed(Status::WT_NEW));
177        expect_false!(flags.is_allowed(Status::WT_MODIFIED));
178        expect_true!(flags.is_allowed(Status::WT_RENAMED));
179        expect_false!(flags.is_allowed(Status::WT_DELETED));
180        expect_false!(flags.is_allowed(Status::WT_TYPECHANGE));
181        expect_false!(flags.is_allowed(Status::WT_UNREADABLE));
182        expect_false!(flags.is_allowed(Status::IGNORED));
183        expect_false!(flags.is_allowed(Status::CONFLICTED));
184    }
185
186    #[gtest]
187    fn test_files_are_included_with_untracked_flag() {
188        let flags = GitFlags::default().with_untracked(true);
189        expect_false!(flags.is_allowed(Status::INDEX_NEW));
190        expect_false!(flags.is_allowed(Status::INDEX_MODIFIED));
191        expect_false!(flags.is_allowed(Status::INDEX_RENAMED));
192        expect_false!(flags.is_allowed(Status::INDEX_DELETED));
193        expect_false!(flags.is_allowed(Status::INDEX_TYPECHANGE));
194        expect_true!(flags.is_allowed(Status::WT_NEW));
195        expect_false!(flags.is_allowed(Status::WT_MODIFIED));
196        expect_false!(flags.is_allowed(Status::WT_RENAMED));
197        expect_false!(flags.is_allowed(Status::WT_DELETED));
198        expect_false!(flags.is_allowed(Status::WT_TYPECHANGE));
199        expect_false!(flags.is_allowed(Status::WT_UNREADABLE));
200        expect_false!(flags.is_allowed(Status::IGNORED));
201        expect_false!(flags.is_allowed(Status::CONFLICTED));
202    }
203
204    #[gtest]
205    fn test_files_are_included_with_ignored_flag() {
206        let flags = GitFlags::default().with_ignored(true);
207        expect_false!(flags.is_allowed(Status::INDEX_NEW));
208        expect_false!(flags.is_allowed(Status::INDEX_MODIFIED));
209        expect_false!(flags.is_allowed(Status::INDEX_RENAMED));
210        expect_false!(flags.is_allowed(Status::INDEX_DELETED));
211        expect_false!(flags.is_allowed(Status::INDEX_TYPECHANGE));
212        expect_false!(flags.is_allowed(Status::WT_NEW));
213        expect_false!(flags.is_allowed(Status::WT_MODIFIED));
214        expect_false!(flags.is_allowed(Status::WT_RENAMED));
215        expect_false!(flags.is_allowed(Status::WT_DELETED));
216        expect_false!(flags.is_allowed(Status::WT_TYPECHANGE));
217        expect_false!(flags.is_allowed(Status::WT_UNREADABLE));
218        expect_true!(flags.is_allowed(Status::IGNORED));
219        expect_false!(flags.is_allowed(Status::CONFLICTED));
220    }
221
222    #[gtest]
223    fn test_files_are_included_with_multiple_flags() {
224        let flags = GitFlags::default().with_added(true).with_modified(true).with_renamed(true);
225        expect_true!(flags.is_allowed(Status::INDEX_NEW));
226        expect_true!(flags.is_allowed(Status::INDEX_MODIFIED));
227        expect_true!(flags.is_allowed(Status::INDEX_RENAMED));
228        expect_false!(flags.is_allowed(Status::INDEX_DELETED));
229        expect_false!(flags.is_allowed(Status::INDEX_TYPECHANGE));
230        expect_false!(flags.is_allowed(Status::WT_NEW));
231        expect_true!(flags.is_allowed(Status::WT_MODIFIED));
232        expect_true!(flags.is_allowed(Status::WT_RENAMED));
233        expect_false!(flags.is_allowed(Status::WT_DELETED));
234        expect_false!(flags.is_allowed(Status::WT_TYPECHANGE));
235        expect_false!(flags.is_allowed(Status::WT_UNREADABLE));
236        expect_false!(flags.is_allowed(Status::IGNORED));
237        expect_false!(flags.is_allowed(Status::CONFLICTED));
238    }
239}