1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
use std::fs::{metadata, write};
use std::io::Error as IoError;
use std::path::{Path, PathBuf};
use git2::{Config as GitConfig, Error as GitError};
/// The default branch to use when initializing and creating commits, this
/// currently only effects LFS backed raw-file repositories.
pub const DEFAULT_GIT_BRANCH: &str = "main";
/// Default path used to setup Lorry's git configuration file.
/// TODO: Should support XDG style configuration and maybe others.
pub const DEFAULT_GIT_CONFIG_PATH: &str = "lorry.gitconfig";
/// Environment variable that specifies where the global git configuration is
/// located. This needs to be configured each time we shell out to Git.
pub const GIT_CONFIG_GLOBAL: &str = "GIT_CONFIG_GLOBAL";
/// Default username used for basic authentication during LFS operations
pub const GITLAB_OAUTH_USER: &str = "oauth2";
/// An error that occurred while access the global git configuration.
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Git Configuration Invalid: {0}")]
Git(#[from] GitError),
#[error("IO Failure: {0}")]
Io(#[from] IoError),
}
/// Ensure that the global git configuration is initialized and has the correct
/// contents. Each time Lorry starts up this file will be setup with required
/// values but additional options can be added as desired.
pub struct Config(pub PathBuf);
impl Config {
/// Setup the Lorry specific git configuration, admin_contact should be a
/// valid e-mail address and will be used in automated commits made by
/// Lorry.
pub fn setup(
&self,
admin_email: &str,
n_threads: i64,
no_ssl_verify: bool,
ask_pass_program: &Path,
) -> Result<(), Error> {
if metadata(&self.0).is_err() {
write(&self.0, [])?;
}
let mut cfg = GitConfig::open(&self.0)?;
cfg.set_str("user.name", "Lorry")?;
cfg.set_str("user.email", admin_email)?;
// do not fork a background process for doing garbage collection
cfg.set_bool("gc.autodetach", false)?;
// number of threads used when pushing to a remote
cfg.set_i64("pack.threads", n_threads)?;
// if ssl cerficates from http sources should be verified
cfg.set_bool("http.sslVerify", !no_ssl_verify)?;
// Extra header exposed by Lorry
cfg.set_str("http.extraHeader", crate::LORRY_VERSION_HEADER)?;
// default branch when initializing repositories
cfg.set_str("init.defaultBranch", DEFAULT_GIT_BRANCH)?;
// global credential specifier used only for LFS operations with
// downstream gitlab, defaults to reading LORRY_GITLAB_PRIVATE_TOKEN
cfg.set_str("credential.username", GITLAB_OAUTH_USER)?;
// program responsible for reading the downstream oauth password
cfg.set_str("core.askPass", &ask_pass_program.to_string_lossy())?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::git_config::Config as GitConfig;
use tempfile::tempdir;
#[test]
pub fn test_rawfile_init() {
let test_dir = tempdir().unwrap();
let git_config_path = test_dir.path().join("gitconfig");
let git_config = GitConfig(git_config_path);
git_config
.setup("hello@example.org", 1, false, Path::new("/dev/null"))
.unwrap();
}
}