1use std::{path::PathBuf, str::FromStr};
2
3use tracing::instrument;
4
5#[allow(dead_code)]
6#[derive(Debug, Clone)]
7pub struct GitFile {
8 pub mode: String,
9 pub path: PathBuf,
10}
11
12impl std::fmt::Display for GitFile {
13 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 write!(f, "{}", self.path.display())
15 }
16}
17
18impl GitFile {
19 #[instrument]
20 pub fn parse(line: impl ToString + std::fmt::Debug) -> Option<GitFile> {
21 let line = line.to_string();
22 let (mode, path_str) = line.trim().split_once(" ")?;
23 let path = PathBuf::from_str(path_str).ok()?;
24 if mode.trim().is_empty() {
25 None
26 } else {
27 Some(GitFile {
28 mode: mode.trim().to_string(),
29 path,
30 })
31 }
32 }
33}
34
35#[derive(Debug, Clone, Default)]
36pub struct GitFiles(Vec<GitFile>);
37
38impl GitFiles {
39 pub fn new() -> Self {
41 Self::default()
42 }
43}
44
45impl std::ops::Deref for GitFiles {
46 type Target = Vec<GitFile>;
47
48 fn deref(&self) -> &Vec<GitFile> {
49 &self.0
50 }
51}
52
53impl std::ops::DerefMut for GitFiles {
54 fn deref_mut(&mut self) -> &mut Self::Target {
55 &mut self.0
56 }
57}
58
59impl AsRef<Vec<GitFile>> for GitFiles {
60 fn as_ref(&self) -> &Vec<GitFile> {
61 &self.0
62 }
63}
64
65impl AsMut<Vec<GitFile>> for GitFiles {
66 fn as_mut(&mut self) -> &mut Vec<GitFile> {
67 &mut self.0
68 }
69}
70
71impl std::fmt::Display for GitFiles {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 for file in self.0.iter() {
74 write!(f, "\n{}", file)?;
75 }
76 Ok(())
77 }
78}
79
80impl GitFiles {
81 #[instrument]
82 pub fn parse(lines: String) -> Option<Self> {
85 let lines = lines.lines();
86 let mut ret = Vec::new();
87 for line in lines {
88 if let Some(gfile) = GitFile::parse(line) {
89 ret.push(gfile);
90 }
91 }
92 if ret.is_empty() {
93 None
94 } else {
95 Some(GitFiles(ret))
96 }
97 }
98}