1use anyhow::{bail, Result};
2use git2::{Config, Repository};
3use std::path::Path;
4use tracing::warn;
5
6const DANGEROUS_SET_KEYS: &[&str] = &[
8 "core.fsmonitor",
9 "core.sshcommand",
10 "core.gitproxy",
11 "core.hookspath",
12 "filter.",
13 "credential.helper",
14 "include.path",
15 "url.",
16];
17
18fn open_config(path: &Path, global: bool) -> Result<Config> {
19 if global {
20 let config = Config::open_default()?;
21 Ok(config.open_level(git2::ConfigLevel::Global)?)
22 } else {
23 let repo = Repository::open(path)?;
24 Ok(repo.config()?)
25 }
26}
27
28pub fn get(path: &Path, key: &str, global: bool) -> Result<()> {
29 let config = open_config(path, global)?;
30
31 match config.get_string(key) {
32 Ok(val) => println!("{}", val),
33 Err(_) => bail!("key '{}' not found", key),
34 }
35
36 Ok(())
37}
38
39pub fn set(path: &Path, key: &str, value: &str, global: bool) -> Result<()> {
40 let key_lower = key.to_lowercase();
41 for dangerous in DANGEROUS_SET_KEYS {
42 if key_lower.starts_with(dangerous) {
43 warn!(
44 "WARNING: Setting '{}' can enable code execution. Proceed with caution.",
45 key
46 );
47 eprintln!(
48 "WARNING: Setting '{}' can enable code execution. Proceed with caution.",
49 key
50 );
51 }
52 }
53
54 let mut config = open_config(path, global)?;
55 config.set_str(key, value)?;
56
57 Ok(())
58}
59
60pub fn list(path: &Path, global: bool) -> Result<()> {
61 let config = open_config(path, global)?;
62 let mut entries = config.entries(None)?;
63
64 while let Some(entry) = entries.next() {
65 let entry = entry?;
66 if let (Some(name), Some(value)) = (entry.name(), entry.value()) {
67 println!("{}={}", name, value);
68 }
69 }
70
71 Ok(())
72}