diff --git a/Cargo.lock b/Cargo.lock index 790d2b37..349ca717 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -531,9 +531,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.16.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "openssl-probe" @@ -701,6 +701,7 @@ dependencies = [ "flate2", "git2", "indexmap", + "once_cell", "serde", "serde_json", "strsim", diff --git a/Cargo.toml b/Cargo.toml index a0137855..370d6b08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ strsim = "0.10" tempfile = "3" termcolor = "1.1" thiserror = "~1.0" +once_cell = "~1.14" bzip2 = { version = "0.4", optional = true } curl = { version = "0.4", optional = true } @@ -47,6 +48,7 @@ flate2 = { version = "1", optional = true } tar = { version = "0.4", optional = true } [features] -default = ["import-compressed", "import-url"] +default = ["import-compressed", "import-url", "git2-ext-worktreeconfig-support"] import-compressed = ["dep:bzip2", "dep:flate2", "dep:tar"] import-url = ["dep:curl"] +git2-ext-worktreeconfig-support = [] diff --git a/src/main.rs b/src/main.rs index c9ed8639..ee76768b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,6 +42,34 @@ const COMMAND_ERROR: i32 = 2; /// Process exit code for when a command halts due to merge conflicts. const CONFLICT_ERROR: i32 = 3; +/// Initialize [`git2`] library. +/// +/// [`git2`] library by default fails any operation if it encounters any extensions configured in a repo. +/// [`stg`] is using [`git2`] library as an interface to object database and for looking alias lookup from git configuration. +/// +/// As a workaround until `worktreeconfig` extension is supported upstream, add it to whitelisted extensions. +/// +/// # Safety +/// * Modifying whitelisted extensions in [`git2`] is like modifying a static mut variable (unsafe). +/// * This function must be called at initialization time (before git2 library usage) and should be called only once. +unsafe fn init_libgit2() -> Result<()> { + if cfg!(feature = "git2-ext-worktreeconfig-support") { + return git2::opts::set_extensions(&["worktreeconfig"]) + .context("Failed to set worktreeconfig extension"); + } + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_me() { + unsafe { init_libgit2() }.expect("success"); + } +} + /// Create base [`clap::Command`] instance. /// /// The base [`clap::Command`] returned by this function is intended to be supplemented @@ -138,6 +166,9 @@ pub(crate) fn get_full_command( /// The name of the game is to dispatch to the appropriate subcommand or alias as /// quickly as possible. fn main() -> ! { + // Initialize git2 library. + unsafe { init_libgit2() }.expect("Failed libgit2 init"); + let argv: Vec = std::env::args_os().collect(); // Chicken and egg: the --color option must be parsed from argv in order to setup