rustic_git/commands/config.rs
1use crate::utils::git;
2use crate::{Repository, Result};
3
4/// Repository configuration manager
5///
6/// Provides methods for getting and setting git configuration values
7/// for a specific repository.
8pub struct RepoConfig<'a> {
9 repo: &'a Repository,
10}
11
12impl<'a> RepoConfig<'a> {
13 /// Create a new RepoConfig instance
14 pub(crate) fn new(repo: &'a Repository) -> Self {
15 Self { repo }
16 }
17
18 pub const USER_NAME_KEY: &'static str = "user.name";
19 pub const USER_EMAIL_KEY: &'static str = "user.email";
20
21 /// Configure git user name and email for this repository
22 ///
23 /// This is a convenience method that sets both user.name and user.email
24 /// configuration values.
25 ///
26 /// # Arguments
27 ///
28 /// * `name` - The user's full name
29 /// * `email` - The user's email address
30 ///
31 /// # Example
32 ///
33 /// ```rust
34 /// use rustic_git::Repository;
35 /// use std::{env, fs};
36 ///
37 /// let test_path = env::temp_dir().join("config_set_user_test");
38 /// if test_path.exists() {
39 /// fs::remove_dir_all(&test_path).unwrap();
40 /// }
41 ///
42 /// let repo = Repository::init(&test_path, false)?;
43 /// repo.config().set_user("John Doe", "john@example.com")?;
44 ///
45 /// // Clean up
46 /// fs::remove_dir_all(&test_path).unwrap();
47 /// # Ok::<(), rustic_git::GitError>(())
48 /// ```
49 pub fn set_user(&self, name: &str, email: &str) -> Result<()> {
50 self.set(Self::USER_NAME_KEY, name)?;
51 self.set(Self::USER_EMAIL_KEY, email)?;
52 Ok(())
53 }
54
55 /// Get the current git user configuration
56 ///
57 /// Returns a tuple of (name, email) from the repository configuration.
58 ///
59 /// # Returns
60 ///
61 /// A tuple containing the user name and email, or an error if either
62 /// configuration value is not set.
63 pub fn get_user(&self) -> Result<(String, String)> {
64 let name = self.get(Self::USER_NAME_KEY)?;
65 let email = self.get(Self::USER_EMAIL_KEY)?;
66 Ok((name, email))
67 }
68
69 /// Set a git configuration value for this repository
70 ///
71 /// # Arguments
72 ///
73 /// * `key` - The configuration key (e.g., "user.name", "core.autocrlf")
74 /// * `value` - The value to set
75 ///
76 /// # Example
77 ///
78 /// ```rust
79 /// use rustic_git::Repository;
80 /// use std::{env, fs};
81 ///
82 /// let test_path = env::temp_dir().join("config_set_test");
83 /// if test_path.exists() {
84 /// fs::remove_dir_all(&test_path).unwrap();
85 /// }
86 ///
87 /// let repo = Repository::init(&test_path, false)?;
88 /// repo.config().set("core.autocrlf", "false")?;
89 /// repo.config().set("user.name", "Jane Doe")?;
90 ///
91 /// // Clean up
92 /// fs::remove_dir_all(&test_path).unwrap();
93 /// # Ok::<(), rustic_git::GitError>(())
94 /// ```
95 pub fn set(&self, key: &str, value: &str) -> Result<()> {
96 git(&["config", key, value], Some(self.repo.repo_path()))?;
97 Ok(())
98 }
99
100 /// Get a git configuration value from this repository
101 ///
102 /// # Arguments
103 ///
104 /// * `key` - The configuration key to retrieve
105 ///
106 /// # Returns
107 ///
108 /// The configuration value as a string, or an error if the key is not found.
109 ///
110 /// # Example
111 ///
112 /// ```rust
113 /// use rustic_git::Repository;
114 /// use std::{env, fs};
115 ///
116 /// let test_path = env::temp_dir().join("config_get_test");
117 /// if test_path.exists() {
118 /// fs::remove_dir_all(&test_path).unwrap();
119 /// }
120 ///
121 /// let repo = Repository::init(&test_path, false)?;
122 /// repo.config().set("user.name", "Jane Doe")?;
123 /// let name = repo.config().get("user.name")?;
124 /// assert_eq!(name, "Jane Doe");
125 ///
126 /// // Clean up
127 /// fs::remove_dir_all(&test_path).unwrap();
128 /// # Ok::<(), rustic_git::GitError>(())
129 /// ```
130 pub fn get(&self, key: &str) -> Result<String> {
131 git(&["config", key], Some(self.repo.repo_path())).map(|s| s.trim().to_string())
132 }
133
134 /// Remove a git configuration value from this repository
135 ///
136 /// # Arguments
137 ///
138 /// * `key` - The configuration key to remove
139 ///
140 /// # Example
141 ///
142 /// ```rust
143 /// use rustic_git::Repository;
144 /// use std::{env, fs};
145 ///
146 /// let test_path = env::temp_dir().join("config_unset_test");
147 /// if test_path.exists() {
148 /// fs::remove_dir_all(&test_path).unwrap();
149 /// }
150 ///
151 /// let repo = Repository::init(&test_path, false)?;
152 /// repo.config().set("test.value", "temporary")?;
153 /// repo.config().unset("test.value")?;
154 ///
155 /// // Clean up
156 /// fs::remove_dir_all(&test_path).unwrap();
157 /// # Ok::<(), rustic_git::GitError>(())
158 /// ```
159 pub fn unset(&self, key: &str) -> Result<()> {
160 git(&["config", "--unset", key], Some(self.repo.repo_path()))?;
161 Ok(())
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168 use std::env;
169 use std::fs;
170
171 #[test]
172 fn test_config_set_and_get_user() {
173 let test_path = env::temp_dir().join("test_config_user");
174
175 // Clean up if exists
176 if test_path.exists() {
177 fs::remove_dir_all(&test_path).unwrap();
178 }
179
180 let repo = Repository::init(&test_path, false).unwrap();
181
182 // Set user configuration
183 repo.config()
184 .set_user("Test User", "test@example.com")
185 .unwrap();
186
187 // Get user configuration
188 let (name, email) = repo.config().get_user().unwrap();
189 assert_eq!(name, "Test User");
190 assert_eq!(email, "test@example.com");
191
192 // Clean up
193 fs::remove_dir_all(&test_path).unwrap();
194 }
195
196 #[test]
197 fn test_config_set_and_get_generic() {
198 let test_path = env::temp_dir().join("test_config_generic");
199
200 // Clean up if exists
201 if test_path.exists() {
202 fs::remove_dir_all(&test_path).unwrap();
203 }
204
205 let repo = Repository::init(&test_path, false).unwrap();
206
207 // Set generic configuration
208 repo.config().set("core.autocrlf", "false").unwrap();
209 repo.config().set("user.name", "Generic User").unwrap();
210
211 // Get generic configuration
212 let autocrlf = repo.config().get("core.autocrlf").unwrap();
213 let name = repo.config().get("user.name").unwrap();
214
215 assert_eq!(autocrlf, "false");
216 assert_eq!(name, "Generic User");
217
218 // Clean up
219 fs::remove_dir_all(&test_path).unwrap();
220 }
221
222 #[test]
223 fn test_config_unset() {
224 let test_path = env::temp_dir().join("test_config_unset");
225
226 // Clean up if exists
227 if test_path.exists() {
228 fs::remove_dir_all(&test_path).unwrap();
229 }
230
231 let repo = Repository::init(&test_path, false).unwrap();
232
233 // Set a test value
234 repo.config().set("test.temporary", "value").unwrap();
235 let value = repo.config().get("test.temporary").unwrap();
236 assert_eq!(value, "value");
237
238 // Unset the value
239 repo.config().unset("test.temporary").unwrap();
240
241 // Verify it's gone (should return error)
242 let result = repo.config().get("test.temporary");
243 assert!(result.is_err());
244
245 // Clean up
246 fs::remove_dir_all(&test_path).unwrap();
247 }
248
249 #[test]
250 fn test_config_get_nonexistent_key() {
251 let test_path = env::temp_dir().join("test_config_nonexistent");
252
253 // Clean up if exists
254 if test_path.exists() {
255 fs::remove_dir_all(&test_path).unwrap();
256 }
257
258 let repo = Repository::init(&test_path, false).unwrap();
259
260 // Try to get a non-existent key
261 let result = repo.config().get("nonexistent.key");
262 assert!(result.is_err());
263
264 // Clean up
265 fs::remove_dir_all(&test_path).unwrap();
266 }
267
268 #[test]
269 fn test_config_integration_with_commit() {
270 let test_path = env::temp_dir().join("test_config_commit_integration");
271
272 // Clean up if exists
273 if test_path.exists() {
274 fs::remove_dir_all(&test_path).unwrap();
275 }
276
277 let repo = Repository::init(&test_path, false).unwrap();
278
279 // Configure user for commits
280 repo.config()
281 .set_user("Integration Test", "integration@example.com")
282 .unwrap();
283
284 // Create a file and commit
285 std::fs::write(test_path.join("test.txt"), "test content").unwrap();
286 repo.add(&["test.txt"]).unwrap();
287 let hash = repo.commit("Test commit with config API").unwrap();
288
289 // Verify commit was created successfully
290 assert!(!hash.as_str().is_empty());
291
292 // Clean up
293 fs::remove_dir_all(&test_path).unwrap();
294 }
295}