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