Skip to main content

git_su/
git.rs

1// Git: config get/set/unset, scopes local/global/system
2
3use crate::shell;
4use crate::user::User;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum Scope {
8    Local,
9    Global,
10    System,
11    Derived,
12    Default,
13}
14
15impl Scope {
16    pub fn as_flag(self) -> &'static str {
17        match self {
18            Scope::Local => "local",
19            Scope::Global => "global",
20            Scope::System => "system",
21            Scope::Derived | Scope::Default => "",
22        }
23    }
24
25    pub fn display_name(self) -> &'static str {
26        match self {
27            Scope::Local => "local",
28            Scope::Global => "global",
29            Scope::System => "system",
30            Scope::Derived => "derived",
31            Scope::Default => "local",
32        }
33    }
34}
35
36pub struct Git;
37
38impl Git {
39    pub fn get_config(scope: Scope, key: &str) -> String {
40        let suffix = format!("--get {}", key);
41        let cmd = if scope == Scope::Derived {
42            format!("git config {}", suffix)
43        } else {
44            format!("git config --{} {}", scope.as_flag(), suffix)
45        };
46        shell::capture(&cmd)
47    }
48
49    pub fn set_config(scope: Scope, key: &str, value: &str) -> bool {
50        let escaped = value.replace("'", "'\\''");
51        let suffix = format!("{} '{}'", key, escaped);
52        let cmd = if scope == Scope::Derived {
53            format!("git config {}", suffix)
54        } else {
55            format!("git config --{} {}", scope.as_flag(), suffix)
56        };
57        shell::execute(&cmd)
58    }
59
60    pub fn unset_config(scope: Scope, key: &str) -> bool {
61        let suffix = format!("--unset {}", key);
62        let cmd = if scope == Scope::Derived {
63            format!("git config {}", suffix)
64        } else {
65            format!("git config --{} {}", scope.as_flag(), suffix)
66        };
67        shell::execute(&cmd)
68    }
69
70    pub fn list_config(scope: Scope) -> Vec<String> {
71        let suffix = "--list";
72        let cmd = if scope == Scope::Derived {
73            format!("git config {}", suffix)
74        } else {
75            format!("git config --{} {}", scope.as_flag(), suffix)
76        };
77        let s = shell::capture(&cmd);
78        if s.is_empty() {
79            return vec![];
80        }
81        s.lines().map(str::to_string).collect()
82    }
83
84    pub fn remove_section(scope: Scope, section: &str) -> bool {
85        let suffix = format!("--remove-section {} 2>/dev/null", section);
86        let cmd = if scope == Scope::Derived {
87            format!("git config {}", suffix)
88        } else {
89            format!("git config --{} {}", scope.as_flag(), suffix)
90        };
91        shell::execute(&cmd)
92    }
93
94    pub fn select_user(user: &User, scope: Scope) -> bool {
95        Self::set_config(scope, "user.name", &user.name())
96            && Self::set_config(scope, "user.email", &user.email())
97    }
98
99    pub fn selected_user(scope: Scope) -> User {
100        let name = Self::get_config(scope, "user.name");
101        if name.is_empty() {
102            return User::none();
103        }
104        let email = Self::get_config(scope, "user.email");
105        User::new(name, email)
106    }
107
108    pub fn clear_user(scope: Scope) {
109        let current = Self::selected_user(scope);
110        if current.is_none() {
111            return;
112        }
113        Self::unset_config(scope, "user.name");
114        Self::unset_config(scope, "user.email");
115        let list = Self::list_config(scope);
116        if list.iter().filter(|e| e.starts_with("user.")).count() == 0 {
117            Self::remove_section(scope, "user");
118        }
119    }
120
121    pub fn edit_gitsu_config(path: &std::path::Path) -> bool {
122        let path_str = path.to_string_lossy();
123        let cmd = format!("git config --edit --file {}", path_str);
124        shell::execute(&cmd)
125    }
126
127    pub fn get_color(name: &str) -> String {
128        let suffix = format!("--get-color '' '{}'", name);
129        let cmd = format!("git config {}", suffix);
130        shell::capture(&cmd)
131    }
132
133    pub fn color_output() -> bool {
134        let cmd = "git config --get-colorbool color.ui";
135        let v = shell::capture(cmd);
136        v == "true" || v == "always"
137    }
138
139    pub fn render(user: &User) -> String {
140        if Self::color_output() {
141            let user_color = Self::get_color("blue");
142            let email_color = Self::get_color("green");
143            let reset = Self::get_color("reset");
144            format!(
145                "{}{} {}<{}>{}",
146                user_color,
147                user.name(),
148                email_color,
149                user.email(),
150                reset
151            )
152        } else {
153            user.to_string()
154        }
155    }
156}