gnostr_asyncgit/sync/
config.rs

1//TODO: hopefully released in next rust (see https://github.com/rust-lang/rust-clippy/issues/9440)
2#![allow(clippy::use_self)]
3
4use git2::Repository;
5use scopetime::scope_time;
6use serde::{Deserialize, Serialize};
7
8use super::{RepoPath, repository::repo};
9use crate::error::Result;
10
11// see https://git-scm.com/docs/git-config#Documentation/git-config.txt-statusshowUntrackedFiles
12/// represents the `status.showUntrackedFiles` git config state
13#[derive(
14	Hash, Copy, Clone, PartialEq, Eq, Serialize, Deserialize,
15)]
16pub enum ShowUntrackedFilesConfig {
17	///
18	No,
19	///
20	Normal,
21	///
22	All,
23}
24
25impl Default for ShowUntrackedFilesConfig {
26	fn default() -> Self {
27		Self::No
28	}
29}
30
31impl ShowUntrackedFilesConfig {
32	///
33	pub const fn include_none(self) -> bool {
34		matches!(self, Self::No)
35	}
36
37	///
38	pub const fn include_untracked(self) -> bool {
39		matches!(self, Self::Normal | Self::All)
40	}
41
42	///
43	pub const fn recurse_untracked_dirs(self) -> bool {
44		matches!(self, Self::All)
45	}
46}
47
48pub fn untracked_files_config_repo(
49	repo: &Repository,
50) -> Result<ShowUntrackedFilesConfig> {
51	let show_untracked_files =
52		get_config_string_repo(repo, "status.showUntrackedFiles")?;
53
54	if let Some(show_untracked_files) = show_untracked_files {
55		if &show_untracked_files == "no" {
56			return Ok(ShowUntrackedFilesConfig::No);
57		} else if &show_untracked_files == "normal" {
58			return Ok(ShowUntrackedFilesConfig::Normal);
59		}
60	}
61
62	Ok(ShowUntrackedFilesConfig::All)
63}
64
65///
66pub fn untracked_files_config(
67	repo_path: &RepoPath,
68) -> Result<ShowUntrackedFilesConfig> {
69	let repo = repo(repo_path)?;
70	untracked_files_config_repo(&repo)
71}
72
73/// get string from config
74
75pub fn get_config_string(
76	repo_path: &RepoPath,
77	key: &str,
78) -> Result<Option<String>> {
79	let repo = repo(repo_path)?;
80	get_config_string_repo(&repo, key)
81}
82
83pub fn get_config_string_repo(
84	repo: &Repository,
85	key: &str,
86) -> Result<Option<String>> {
87	scope_time!("get_config_string_repo");
88
89	let cfg = repo.config()?;
90
91	// this code doesn't match what the doc says regarding what
92	// gets returned when but it actually works
93	let entry_res = cfg.get_entry(key);
94
95	let Ok(entry) = entry_res else {
96		return Ok(None);
97	};
98
99	if entry.has_value() {
100		Ok(entry.value().map(std::string::ToString::to_string))
101	} else {
102		Ok(None)
103	}
104}
105
106#[cfg(test)]
107mod tests {
108	use super::*;
109	use crate::sync::tests::repo_init;
110
111	#[test]
112	fn test_get_config() {
113		let bad_dir_cfg = get_config_string(
114			&"oodly_noodly".into(),
115			"this.doesnt.exist",
116		);
117		assert!(bad_dir_cfg.is_err());
118
119		let (_td, repo) = repo_init().unwrap();
120		let path = repo.path();
121		let rpath = path.as_os_str().to_str().unwrap();
122		let bad_cfg =
123			get_config_string(&rpath.into(), "this.doesnt.exist");
124		assert!(bad_cfg.is_ok());
125		assert!(bad_cfg.unwrap().is_none());
126		// repo init sets user.name
127		let good_cfg = get_config_string(&rpath.into(), "user.name");
128		assert!(good_cfg.is_ok());
129		assert!(good_cfg.unwrap().is_some());
130	}
131}