diff --git a/libgit2-sys/lib.rs b/libgit2-sys/lib.rs index 951397cc2c..bade631b20 100644 --- a/libgit2-sys/lib.rs +++ b/libgit2-sys/lib.rs @@ -1870,6 +1870,10 @@ git_enum! { GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, GIT_OPT_GET_MWINDOW_FILE_LIMIT, GIT_OPT_SET_MWINDOW_FILE_LIMIT, + GIT_OPT_SET_ODB_PACKED_PRIORITY, + GIT_OPT_SET_ODB_LOOSE_PRIORITY, + GIT_OPT_GET_EXTENSIONS, + GIT_OPT_SET_EXTENSIONS, } } diff --git a/src/opts.rs b/src/opts.rs index 007b272c1b..a89df4e1c9 100644 --- a/src/opts.rs +++ b/src/opts.rs @@ -1,7 +1,9 @@ //! Bindings to libgit2's git_libgit2_opts function. use std::ffi::CString; +use std::ptr; +use crate::string_array::StringArray; use crate::util::Binding; use crate::{raw, Buf, ConfigLevel, Error, IntoCString}; @@ -119,6 +121,63 @@ pub fn strict_hash_verification(enabled: bool) { debug_assert!(error >= 0); } +/// Returns the list of git extensions that are supported. This is the list of +/// built-in extensions supported by libgit2 and custom extensions that have +/// been added with [`set_extensions`]. Extensions that have been negated will +/// not be returned. +/// +/// # Safety +/// +/// libgit2 stores user extensions in a static variable. +/// This function is effectively reading a `static mut` and should be treated as such +pub unsafe fn get_extensions() -> Result { + crate::init(); + + let mut extensions = raw::git_strarray { + strings: ptr::null_mut(), + count: 0, + }; + + try_call!(raw::git_libgit2_opts( + raw::GIT_OPT_GET_EXTENSIONS as libc::c_int, + &mut extensions + )); + + Ok(StringArray::from_raw(extensions)) +} + +/// Set that the given git extensions are supported by the caller. Extensions +/// supported by libgit2 may be negated by prefixing them with a `!`. +/// For example: setting extensions to `[ "!noop", "newext" ]` indicates that +/// the caller does not want to support repositories with the `noop` extension +/// but does want to support repositories with the `newext` extension. +/// +/// # Safety +/// +/// libgit2 stores user extensions in a static variable. +/// This function is effectively modifying a `static mut` and should be treated as such +pub unsafe fn set_extensions(extensions: &[E]) -> Result<(), Error> +where + for<'x> &'x E: IntoCString, +{ + crate::init(); + + let extensions = extensions + .iter() + .map(|e| e.into_c_string()) + .collect::, _>>()?; + + let extension_ptrs = extensions.iter().map(|e| e.as_ptr()).collect::>(); + + try_call!(raw::git_libgit2_opts( + raw::GIT_OPT_SET_EXTENSIONS as libc::c_int, + extension_ptrs.as_ptr(), + extension_ptrs.len() as libc::size_t + )); + + Ok(()) +} + #[cfg(test)] mod test { use super::*; diff --git a/tests/add_extensions.rs b/tests/add_extensions.rs new file mode 100644 index 0000000000..fe37e1eeb7 --- /dev/null +++ b/tests/add_extensions.rs @@ -0,0 +1,19 @@ +//! Test for `set_extensions`, which writes a global state maintained by libgit2 + +use git2::opts::{get_extensions, set_extensions}; +use git2::Error; + +#[test] +fn test_add_extensions() -> Result<(), Error> { + unsafe { + set_extensions(&["custom"])?; + } + + let extensions = unsafe { get_extensions() }?; + + assert_eq!(extensions.len(), 2); + assert_eq!(extensions.get(0), Some("noop")); + assert_eq!(extensions.get(1), Some("custom")); + + Ok(()) +} diff --git a/tests/get_extensions.rs b/tests/get_extensions.rs new file mode 100644 index 0000000000..ac049c6816 --- /dev/null +++ b/tests/get_extensions.rs @@ -0,0 +1,14 @@ +//! Test for `get_extensions`, which reads a global state maintained by libgit2 + +use git2::opts::get_extensions; +use git2::Error; + +#[test] +fn test_get_extensions() -> Result<(), Error> { + let extensions = unsafe { get_extensions() }?; + + assert_eq!(extensions.len(), 1); + assert_eq!(extensions.get(0), Some("noop")); + + Ok(()) +} diff --git a/tests/remove_extensions.rs b/tests/remove_extensions.rs new file mode 100644 index 0000000000..366da7392b --- /dev/null +++ b/tests/remove_extensions.rs @@ -0,0 +1,19 @@ +//! Test for `set_extensions`, which writes a global state maintained by libgit2 + +use git2::opts::{get_extensions, set_extensions}; +use git2::Error; + +#[test] +fn test_remove_extensions() -> Result<(), Error> { + unsafe { + set_extensions(&["custom", "!ignore", "!noop", "other"])?; + } + + let extensions = unsafe { get_extensions() }?; + + assert_eq!(extensions.len(), 2); + assert_eq!(extensions.get(0), Some("custom")); + assert_eq!(extensions.get(1), Some("other")); + + Ok(()) +}