Subject: [PATCH v3 3/6] libgit-sys: add repo initialization and config access

From: Calvin Wan <[email-masked]>
Date: Fri, 6 Sep 2024 22:21:13 +0000

Wrap a few repo setup and config access functions in libgit-sys. These
were selected as proof-of-concept items to show that we can access local
config from Rust.

Co-authored-by: Josh Steadmon <[email-masked]>
Signed-off-by: Calvin Wan <[email-masked]>
Change-Id: I6dd886af8c63e1f0f3251064cd8903aecdf768bb
---
 .../libgit-sys/public_symbol_export.c         | 26 +++++++++
 .../libgit-sys/public_symbol_export.h         |  8 +++
 contrib/libgit-rs/libgit-sys/src/lib.rs       | 57 ++++++++++++++++++-
 3 files changed, 89 insertions(+), 2 deletions(-)

diff --git a/contrib/libgit-rs/libgit-sys/public_symbol_export.c b/contrib/libgit-rs/libgit-sys/public_symbol_export.c
index 39c27d9c1a..65d1620d28 100644
--- a/contrib/libgit-rs/libgit-sys/public_symbol_export.c
+++ b/contrib/libgit-rs/libgit-sys/public_symbol_export.c
@@ -2,11 +2,37 @@
 // original symbols can be hidden. Renaming these with a "libgit_" prefix also
 // avoid conflicts with other libraries such as libgit2.
 
+#include "git-compat-util.h"
 #include "contrib/libgit-rs/libgit-sys/public_symbol_export.h"
+#include "common-init.h"
+#include "config.h"
+#include "setup.h"
 #include "version.h"
 
+extern struct repository *the_repository;
+
 #pragma GCC visibility push(default)
 
+const char *libgit_setup_git_directory(void)
+{
+	return setup_git_directory();
+}
+
+int libgit_config_get_int(const char *key, int *dest)
+{
+	return repo_config_get_int(the_repository, key, dest);
+}
+
+void libgit_init_git(const char **argv)
+{
+	init_git(argv);
+}
+
+int libgit_parse_maybe_bool(const char *val)
+{
+	return git_parse_maybe_bool(val);
+}
+
 const char *libgit_user_agent(void)
 {
 	return git_user_agent();
diff --git a/contrib/libgit-rs/libgit-sys/public_symbol_export.h b/contrib/libgit-rs/libgit-sys/public_symbol_export.h
index a3372f93fa..64332f30de 100644
--- a/contrib/libgit-rs/libgit-sys/public_symbol_export.h
+++ b/contrib/libgit-rs/libgit-sys/public_symbol_export.h
@@ -1,6 +1,14 @@
 #ifndef PUBLIC_SYMBOL_EXPORT_H
 #define PUBLIC_SYMBOL_EXPORT_H
 
+const char *libgit_setup_git_directory(void);
+
+int libgit_config_get_int(const char *key, int *dest);
+
+void libgit_init_git(const char **argv);
+
+int libgit_parse_maybe_bool(const char *val);
+
 const char *libgit_user_agent(void);
 
 const char *libgit_user_agent_sanitized(void);
diff --git a/contrib/libgit-rs/libgit-sys/src/lib.rs b/contrib/libgit-rs/libgit-sys/src/lib.rs
index 346b26083d..9b2e85dff8 100644
--- a/contrib/libgit-rs/libgit-sys/src/lib.rs
+++ b/contrib/libgit-rs/libgit-sys/src/lib.rs
@@ -1,8 +1,19 @@
-use std::ffi::c_char;
+use std::ffi::{c_char, c_int};
 
 extern crate libz_sys;
 
 extern "C" {
+    pub fn libgit_setup_git_directory() -> *const c_char;
+
+    // From config.c
+    pub fn libgit_config_get_int(key: *const c_char, dest: *mut c_int) -> c_int;
+
+    // From common-init.c
+    pub fn libgit_init_git(argv: *const *const c_char);
+
+    // From parse.c
+    pub fn libgit_parse_maybe_bool(val: *const c_char) -> c_int;
+
     // From version.c
     pub fn libgit_user_agent() -> *const c_char;
     pub fn libgit_user_agent_sanitized() -> *const c_char;
@@ -10,7 +21,7 @@ extern "C" {
 
 #[cfg(test)]
 mod tests {
-    use std::ffi::CStr;
+    use std::ffi::{CStr, CString};
 
     use super::*;
 
@@ -39,4 +50,46 @@ mod tests {
             agent
         );
     }
+
+    #[test]
+    fn parse_bools_from_strings() {
+        let arg = CString::new("true").unwrap();
+        assert_eq!(unsafe { libgit_parse_maybe_bool(arg.as_ptr()) }, 1);
+
+        let arg = CString::new("yes").unwrap();
+        assert_eq!(unsafe { libgit_parse_maybe_bool(arg.as_ptr()) }, 1);
+
+        let arg = CString::new("false").unwrap();
+        assert_eq!(unsafe { libgit_parse_maybe_bool(arg.as_ptr()) }, 0);
+
+        let arg = CString::new("no").unwrap();
+        assert_eq!(unsafe { libgit_parse_maybe_bool(arg.as_ptr()) }, 0);
+
+        let arg = CString::new("maybe").unwrap();
+        assert_eq!(unsafe { libgit_parse_maybe_bool(arg.as_ptr()) }, -1);
+    }
+
+    #[test]
+    fn access_configs() {
+        /*
+         * Since we can't easily set a config for the local repo, test
+         * for the existence of a key rather than a specific value 
+         */
+        let fake_argv = [std::ptr::null::<c_char>()];
+        unsafe {
+            libgit_init_git(fake_argv.as_ptr());
+            libgit_setup_git_directory();
+        }
+        let mut dest: c_int = 0;
+        let key = CString::new("core.repositoryformatversion").unwrap();
+        unsafe { 
+            let val = libgit_config_get_int(key.as_ptr(), &mut dest as *mut i32);
+            assert_eq!(val, 0)
+        };
+        let missing_key = CString::new("foo.bar").unwrap();
+        unsafe { 
+            let val = libgit_config_get_int(missing_key.as_ptr(), &mut dest as *mut i32);
+            assert_eq!(val, 1)
+        };
+    }
 }
-- 
2.46.0.469.g59c65b2a67-goog