1use git2::{Config as GitConfig, Error as GitError};
6use std::fs::{metadata, write};
7use std::io::Error as IoError;
8use std::path::{Path, PathBuf};
9
10pub const DEFAULT_GIT_BRANCH: &str = "main";
13
14pub const DEFAULT_GIT_CONFIG_PATH: &str = "lorry.gitconfig";
17
18pub const GIT_CONFIG_GLOBAL: &str = "GIT_CONFIG_GLOBAL";
21
22pub const GITLAB_OAUTH_USER: &str = "oauth2";
24
25#[derive(thiserror::Error, Debug)]
27pub enum Error {
28 #[error("Git Configuration Invalid: {0}")]
30 Git(#[from] GitError),
31
32 #[error("IO Failure: {0}")]
34 Io(#[from] IoError),
35}
36
37pub struct Config(pub PathBuf);
41
42impl Config {
43 #[tracing::instrument(skip_all, fields(git_cfg_path = self.0.to_str()))]
47 #[allow(clippy::too_many_arguments)]
48 pub fn setup(
49 &self,
50 git_identity: (&str, &str),
51 n_threads: i64,
52 no_ssl_verify: bool,
53 http_version: Option<&str>,
54 ask_pass_program: &Path,
55 git_credentials_file: Option<&Path>,
56 lfs_activity_timeout: Option<i64>,
57 lfs_dial_timeout: Option<i64>,
58 lfs_tls_timeout: Option<i64>,
59 ) -> Result<(), Error> {
60 if metadata(&self.0).is_err() {
61 write(&self.0, [])?;
62 }
63 let mut cfg = GitConfig::open(&self.0)?;
64 cfg.set_str("user.name", git_identity.0)?;
65 cfg.set_str("user.email", git_identity.1)?;
66
67 cfg.set_bool("gc.autodetach", false)?;
69
70 cfg.set_i64("pack.threads", n_threads)?;
72
73 cfg.set_bool("http.sslVerify", !no_ssl_verify)?;
75
76 if let Some(version) = http_version {
78 cfg.set_str("http.version", version)?;
79 }
80
81 cfg.set_str("http.extraHeader", crate::LORRY_VERSION_HEADER)?;
83
84 cfg.set_str("init.defaultBranch", DEFAULT_GIT_BRANCH)?;
86
87 cfg.set_str("credential.username", GITLAB_OAUTH_USER)?;
90
91 cfg.set_str("core.askPass", &ask_pass_program.to_string_lossy())?;
93
94 if let Some(gitcredentials_path) = git_credentials_file {
96 cfg.set_str(
97 "credential.helper",
98 &format!("store --file {}", gitcredentials_path.display()),
99 )?;
100 }
101
102 if let Some(activity_timeout) = lfs_activity_timeout {
103 cfg.set_i64("lfs.activityTimeout", activity_timeout)?;
104 }
105
106 if let Some(dial_timeout) = lfs_dial_timeout {
107 cfg.set_i64("lfs.dialTimeout", dial_timeout)?;
108 }
109
110 if let Some(tls_timeout) = lfs_tls_timeout {
111 cfg.set_i64("lfs.tlsTimeout", tls_timeout)?;
112 }
113
114 tracing::debug!("Initialized git config");
115 Ok(())
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use crate::git_config::Config as GitConfig;
123 use tempfile::tempdir;
124
125 #[test]
126 pub fn test_rawfile_init() {
127 let test_dir = tempdir().unwrap();
128 let git_config_path = test_dir.path().join("gitconfig");
129 let git_config = GitConfig(git_config_path);
130 git_config
131 .setup(
132 ("Lorry", "hello@example.org"),
133 1,
134 false,
135 Some("HTTP/1.1"),
136 Path::new("/dev/null"),
137 None,
138 None,
139 None,
140 None,
141 )
142 .unwrap();
143 }
144
145 #[test]
146 pub fn test_lfs_timeouts_written() {
147 let test_dir = tempdir().unwrap();
148 let git_config_path = test_dir.path().join("gitconfig");
149 let git_config = GitConfig(git_config_path.clone());
150 git_config
151 .setup(
152 ("Lorry", "hello@example.org"),
153 1,
154 false,
155 Some("HTTP/1.1"),
156 Path::new("/dev/null"),
157 None,
158 Some(30),
159 Some(5),
160 None,
161 )
162 .unwrap();
163
164 let cfg = git2::Config::open(&git_config_path).unwrap();
165 assert_eq!(cfg.get_i64("lfs.activityTimeout").unwrap(), 30);
166 assert_eq!(cfg.get_i64("lfs.dialTimeout").unwrap(), 5);
167 }
168
169 #[test]
170 pub fn test_lfs_timeouts_unset_by_default() {
171 let test_dir = tempdir().unwrap();
172 let git_config_path = test_dir.path().join("gitconfig");
173 let git_config = GitConfig(git_config_path.clone());
174 git_config
175 .setup(
176 ("Lorry", "hello@example.org"),
177 1,
178 false,
179 Some("HTTP/1.1"),
180 Path::new("/dev/null"),
181 None,
182 None,
183 None,
184 None,
185 )
186 .unwrap();
187
188 let cfg = git2::Config::open(&git_config_path).unwrap();
189 assert!(cfg.get_i64("lfs.activityTimeout").is_err());
192 assert!(cfg.get_i64("lfs.dialTimeout").is_err());
193 }
194}