All of lore.kernel.org
 help / color / mirror / Atom feed
From: "ions via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Chris Torek <chris.torek@gmail.com>,
	Phillip Wood <phillip.wood123@gmail.com>,
	ions <zara.leonardo@gmail.com>
Subject: [PATCH v3 0/3] libgit-rs: add get_bool() method to ConfigSet
Date: Sat, 27 Sep 2025 03:51:48 +0000	[thread overview]
Message-ID: <pull.1977.v3.git.1758945111.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1977.v2.git.1758931659.gitgitgadget@gmail.com>

Purpose

This pull request introduces a get_bool() method to the ConfigSet module in
the libgit-rs library. The goal is to enhance the functionality of ConfigSet
by providing a way to fetch and handle boolean configuration values more
easily and consistently.

Implementation Details

• Added a get_bool() method to the ConfigSet module.

• The method retrieves configuration values as boolean values, ensuring
proper parsing and error handling.

• This addition simplifies the process of working with boolean
configurations for developers using the ConfigSet module.

Testing

• Added unit tests to verify the correctness of the get_bool() method.

• Tested edge cases to ensure robustness.

ionnss (3):
  po: fix escaped underscores in README.md
  libgit-rs: add get_bool() method to ConfigSet
  libgit-rs: add get_ulong() and get_pathname() methods

 contrib/libgit-rs/src/config.rs    | 83 +++++++++++++++++++++++++++++-
 contrib/libgit-rs/testdata/config3 |  2 +-
 contrib/libgit-rs/testdata/config4 | 13 +++++
 contrib/libgit-sys/src/lib.rs      | 24 ++++++++-
 po/README.md                       |  6 +--
 5 files changed, 121 insertions(+), 7 deletions(-)
 create mode 100644 contrib/libgit-rs/testdata/config4


base-commit: bb69721404348ea2db0a081c41ab6ebfe75bdec8
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1977%2Fionnss%2Fadd-rust-configset-get-bool-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1977/ionnss/add-rust-configset-get-bool-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/1977

Range-diff vs v2:

 1:  d7810781fc = 1:  d7810781fc po: fix escaped underscores in README.md
 3:  43784e3ff9 ! 2:  479c263bc1 libgit-rs: address review feedback for get_bool()
     @@ Metadata
      Author: ionnss <zara.leonardo@gmail.com>
      
       ## Commit message ##
     -    libgit-rs: address review feedback for get_bool()
     +    libgit-rs: add get_bool() method to ConfigSet
      
     -    - Use git_configset_get_bool() C function instead of reimplementing parsing
     -    - Fix libgit_configset_get_bool() function signature in bindings
     -    - Improve .expect() error messages to be more descriptive
     -    - Add comprehensive boolean tests including edge cases (00, 100, 007)
     +    Add support for parsing boolean configuration values using Git's
     +    git_configset_get_bool() C function. This ensures consistent behavior
     +    with Git's native boolean parsing logic.
      
     -    This addresses feedback from Phillip Wood and Chris Torek about using
     -    Git's actual boolean parsing logic rather than duplicating it in Rust.
     +    The method handles all Git boolean formats (true/false, yes/no, on/off,
     +    1/0) and edge cases like "00" and "100" correctly.
     +
     +    Includes comprehensive tests for various boolean formats and edge cases.
      
          Signed-off-by: ionnss <zara.leonardo@gmail.com>
      
       ## contrib/libgit-rs/src/config.rs ##
      @@ contrib/libgit-rs/src/config.rs: impl ConfigSet {
     +             Some(owned_str)
               }
           }
     - 
     ++
      +    /// Load the value for the given key and attempt to parse it as a boolean. Dies with a fatal error
      +    /// if the value cannot be parsed. Returns None if the key is not present.
     -     pub fn get_bool(&mut self, key: &str) -> Option<bool> {
     --        let key = CString::new(key).expect("Couldn't convert key to CString");
     --        let mut val: *mut c_char = std::ptr::null_mut();
     ++    pub fn get_bool(&mut self, key: &str) -> Option<bool> {
      +        let key = CString::new(key).expect("config key should be valid CString");
      +        let mut val: c_int = 0;
     -         unsafe {
     --            if libgit_configset_get_string(self.0, key.as_ptr(), &mut val as *mut *mut c_char) != 0
     --            {
     ++        unsafe {
      +            if libgit_configset_get_bool(self.0, key.as_ptr(), &mut val as *mut c_int) != 0 {
     -                 return None;
     -             }
     --            let borrowed_str = CStr::from_ptr(val);
     --            let owned_str =
     --                String::from(borrowed_str.to_str().expect("Couldn't convert val to str"));
     --            free(val as *mut c_void); // Free the xstrdup()ed pointer from the C side
     --            match owned_str.to_lowercase().as_str() {
     --                "true" | "yes" | "on" | "1" => Some(true),
     --                "false" | "no" | "off" | "0" => Some(false),
     --                _ => None,
     --            }
     -         }
     ++                return None;
     ++            }
     ++        }
      +
      +        Some(val != 0)
     -     }
     ++    }
       }
       
     + impl Default for ConfigSet {
      @@ contrib/libgit-rs/src/config.rs: mod tests {
                   Path::new("testdata/config1"),
                   Path::new("testdata/config2"),
     @@ contrib/libgit-rs/src/config.rs: mod tests {
               assert_eq!(cs.get_int("trace2.eventNesting"), Some(3));
               // ConfigSet returns None for missing key
               assert_eq!(cs.get_string("foo.bar"), None);
     --        // Test boolean parsing
     --        assert_eq!(cs.get_bool("test.booleanValue"), Some(true));
      +        // Test boolean parsing - comprehensive tests
      +        assert_eq!(cs.get_bool("test.boolTrue"), Some(true));
      +        assert_eq!(cs.get_bool("test.boolFalse"), Some(false));
     @@ contrib/libgit-rs/src/config.rs: mod tests {
      +        assert_eq!(cs.get_bool("test.boolZero"), Some(false));
      +        assert_eq!(cs.get_bool("test.boolZeroZero"), Some(false)); // "00" → false
      +        assert_eq!(cs.get_bool("test.boolHundred"), Some(true)); // "100" → true
     -+        assert_eq!(cs.get_bool("test.boolSeven"), Some(true)); // "007" → true
     -         // Test missing boolean key
     -         assert_eq!(cs.get_bool("missing.boolean"), None);
     ++        // Test missing boolean key
     ++        assert_eq!(cs.get_bool("missing.boolean"), None);
           }
     + }
      
       ## contrib/libgit-rs/testdata/config3 ##
      @@
       [trace2]
      -	eventNesting = 3
     --[test]
     --	booleanValue = true
      +	eventNesting = 3
       \ No newline at end of file
      
     @@ contrib/libgit-rs/testdata/config4 (new)
      +	boolZero = 0
      +	boolZeroZero = 00
      +	boolHundred = 100
     -+	boolSeven = 007
      
       ## contrib/libgit-sys/src/lib.rs ##
      @@ contrib/libgit-sys/src/lib.rs: extern "C" {
 2:  a5904a2ac0 ! 3:  1ac8d76819 libgit-rs: add get_bool() method to ConfigSet
     @@ Metadata
      Author: ionnss <zara.leonardo@gmail.com>
      
       ## Commit message ##
     -    libgit-rs: add get_bool() method to ConfigSet
     +    libgit-rs: add get_ulong() and get_pathname() methods
      
     -    Add support for parsing boolean configuration values in the Rust
     -    ConfigSet API. The method follows Git's standard boolean parsing
     -    rules, accepting true/yes/on/1 as true and false/no/off/0 as false.
     +    Expand the ConfigSet API with additional configuration value types:
      
     -    The implementation reuses the existing get_string() infrastructure
     -    and adds case-insensitive boolean parsing logic.
     +    - get_ulong(): Parse unsigned long integers for large numeric values
     +    - get_pathname(): Parse file paths, returning PathBuf for type safety
     +
     +    Both functions follow the same pattern as existing get_* methods,
     +    using Git's C functions for consistent parsing behavior.
     +
     +    Add comprehensive tests covering normal cases, edge cases, and
     +    error handling for all new functionality.
      
          Signed-off-by: ionnss <zara.leonardo@gmail.com>
      
       ## contrib/libgit-rs/src/config.rs ##
     +@@
     + use std::ffi::{c_void, CStr, CString};
     +-use std::path::Path;
     ++use std::path::{Path, PathBuf};
     + 
     + #[cfg(has_std__ffi__c_char)]
     +-use std::ffi::{c_char, c_int};
     ++use std::ffi::{c_char, c_int, c_ulong};
     + 
     + #[cfg(not(has_std__ffi__c_char))]
     + #[allow(non_camel_case_types)]
     +@@ contrib/libgit-rs/src/config.rs: type c_char = i8;
     + #[allow(non_camel_case_types)]
     + type c_int = i32;
     + 
     ++#[cfg(not(has_std__ffi__c_char))]
     ++#[allow(non_camel_case_types)]
     ++type c_ulong = u64;
     ++
     + use libgit_sys::*;
     + 
     + /// A ConfigSet is an in-memory cache for config-like files such as `.gitmodules` or `.gitconfig`.
      @@ contrib/libgit-rs/src/config.rs: impl ConfigSet {
     -             Some(owned_str)
     -         }
     + 
     +         Some(val != 0)
           }
      +
     -+    pub fn get_bool(&mut self, key: &str) -> Option<bool> {
     -+        let key = CString::new(key).expect("Couldn't convert key to CString");
     ++    /// Load the value for the given key and attempt to parse it as an unsigned long. Dies with a fatal error
     ++    /// if the value cannot be parsed. Returns None if the key is not present.
     ++    pub fn get_ulong(&mut self, key: &str) -> Option<u64> {
     ++        let key = CString::new(key).expect("config key should be valid CString");
     ++        let mut val: c_ulong = 0;
     ++        unsafe {
     ++            if libgit_configset_get_ulong(self.0, key.as_ptr(), &mut val as *mut c_ulong) != 0 {
     ++                return None;
     ++            }
     ++        }
     ++        Some(val as u64)
     ++    }
     ++
     ++    /// Load the value for the given key and attempt to parse it as a file path. Dies with a fatal error
     ++    /// if the value cannot be converted to a PathBuf. Returns None if the key is not present.
     ++    pub fn get_pathname(&mut self, key: &str) -> Option<PathBuf> {
     ++        let key = CString::new(key).expect("config key should be valid CString");
      +        let mut val: *mut c_char = std::ptr::null_mut();
      +        unsafe {
     -+            if libgit_configset_get_string(self.0, key.as_ptr(), &mut val as *mut *mut c_char) != 0
     ++            if libgit_configset_get_pathname(self.0, key.as_ptr(), &mut val as *mut *mut c_char)
     ++                != 0
      +            {
      +                return None;
      +            }
      +            let borrowed_str = CStr::from_ptr(val);
     -+            let owned_str =
     -+                String::from(borrowed_str.to_str().expect("Couldn't convert val to str"));
     ++            let owned_str = String::from(
     ++                borrowed_str
     ++                    .to_str()
     ++                    .expect("config path should be valid UTF-8"),
     ++            );
      +            free(val as *mut c_void); // Free the xstrdup()ed pointer from the C side
     -+            match owned_str.to_lowercase().as_str() {
     -+                "true" | "yes" | "on" | "1" => Some(true),
     -+                "false" | "no" | "off" | "0" => Some(false),
     -+                _ => None,
     -+            }
     ++            Some(PathBuf::from(owned_str))
      +        }
      +    }
       }
       
       impl Default for ConfigSet {
      @@ contrib/libgit-rs/src/config.rs: mod tests {
     -         assert_eq!(cs.get_int("trace2.eventNesting"), Some(3));
     -         // ConfigSet returns None for missing key
     -         assert_eq!(cs.get_string("foo.bar"), None);
     -+        // Test boolean parsing
     -+        assert_eq!(cs.get_bool("test.booleanValue"), Some(true));
     -+        // Test missing boolean key
     -+        assert_eq!(cs.get_bool("missing.boolean"), None);
     +         assert_eq!(cs.get_bool("test.boolHundred"), Some(true)); // "100" → true
     +         // Test missing boolean key
     +         assert_eq!(cs.get_bool("missing.boolean"), None);
     ++        // Test ulong parsing
     ++        assert_eq!(cs.get_ulong("test.ulongSmall"), Some(42));
     ++        assert_eq!(cs.get_ulong("test.ulongBig"), Some(4294967296)); // > 32-bit int
     ++        assert_eq!(cs.get_ulong("missing.ulong"), None);
     ++        // Test pathname parsing
     ++        assert_eq!(
     ++            cs.get_pathname("test.pathRelative"),
     ++            Some(PathBuf::from("./some/path"))
     ++        );
     ++        assert_eq!(
     ++            cs.get_pathname("test.pathAbsolute"),
     ++            Some(PathBuf::from("/usr/bin/git"))
     ++        );
     ++        assert_eq!(cs.get_pathname("missing.path"), None);
           }
       }
      
     - ## contrib/libgit-rs/testdata/config3 ##
     + ## contrib/libgit-rs/testdata/config4 ##
     +@@
     + 	boolZero = 0
     + 	boolZeroZero = 00
     + 	boolHundred = 100
     ++	ulongSmall = 42
     ++	ulongBig = 4294967296
     ++	pathRelative = ./some/path
     ++	pathAbsolute = /usr/bin/git
     +
     + ## contrib/libgit-sys/src/lib.rs ##
      @@
     - [trace2]
     - 	eventNesting = 3
     -+[test]
     -+	booleanValue = true
     + use std::ffi::c_void;
     + 
     + #[cfg(has_std__ffi__c_char)]
     +-use std::ffi::{c_char, c_int};
     ++use std::ffi::{c_char, c_int, c_ulong};
     + 
     + #[cfg(not(has_std__ffi__c_char))]
     + #[allow(non_camel_case_types)]
     +@@ contrib/libgit-sys/src/lib.rs: pub type c_char = i8;
     + #[allow(non_camel_case_types)]
     + pub type c_int = i32;
     + 
     ++#[cfg(not(has_std__ffi__c_char))]
     ++#[allow(non_camel_case_types)]
     ++pub type c_ulong = u64;
     ++
     + extern crate libz_sys;
     + 
     + #[allow(non_camel_case_types)]
     +@@ contrib/libgit-sys/src/lib.rs: extern "C" {
     +         dest: *mut c_int,
     +     ) -> c_int;
     + 
     ++    pub fn libgit_configset_get_ulong(
     ++        cs: *mut libgit_config_set,
     ++        key: *const c_char,
     ++        dest: *mut c_ulong,
     ++    ) -> c_int;
     ++
     ++    pub fn libgit_configset_get_pathname(
     ++        cs: *mut libgit_config_set,
     ++        key: *const c_char,
     ++        dest: *mut *mut c_char,
     ++    ) -> c_int;
     ++
     + }
     + 
     + #[cfg(test)]

-- 
gitgitgadget

  parent reply	other threads:[~2025-09-27  3:51 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-25 11:44 [PATCH 0/2] libgit-rs: add get_bool() method to ConfigSet ions via GitGitGadget
2025-09-25 11:44 ` [PATCH 1/2] po: fix escaped underscores in README.md ionnss via GitGitGadget
2025-09-25 11:44 ` [PATCH 2/2] libgit-rs: add get_bool() method to ConfigSet ionnss via GitGitGadget
2025-09-26  6:43   ` Chris Torek
2025-09-26  9:58   ` Phillip Wood
2025-09-26 17:15     ` Junio C Hamano
2025-09-27  0:07 ` [PATCH v2 0/3] " ions via GitGitGadget
2025-09-27  0:07   ` [PATCH v2 1/3] po: fix escaped underscores in README.md ionnss via GitGitGadget
2025-09-27  0:07   ` [PATCH v2 2/3] libgit-rs: add get_bool() method to ConfigSet ionnss via GitGitGadget
2025-09-27  0:07   ` [PATCH v2 3/3] libgit-rs: address review feedback for get_bool() ionnss via GitGitGadget
2025-09-27  2:01   ` [PATCH v2 0/3] libgit-rs: add get_bool() method to ConfigSet Junio C Hamano
2025-09-27  3:51   ` ions via GitGitGadget [this message]
2025-09-27  3:51     ` [PATCH v3 1/3] po: fix escaped underscores in README.md ionnss via GitGitGadget
2025-09-29 13:26       ` Phillip Wood
2025-09-27  3:51     ` [PATCH v3 2/3] libgit-rs: add get_bool() method to ConfigSet ionnss via GitGitGadget
2025-09-29 13:23       ` Phillip Wood
2025-09-27  3:51     ` [PATCH v3 3/3] libgit-rs: add get_ulong() and get_pathname() methods ionnss via GitGitGadget
2025-09-29 13:23       ` Phillip Wood
2025-09-30  8:46     ` [PATCH v4] libgit-rs: add get_bool(), get_ulong(), " ions via GitGitGadget
2025-10-01 10:15       ` Phillip Wood
2025-10-06 21:20         ` brian m. carlson
2025-10-08 13:36           ` Phillip Wood

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=pull.1977.v3.git.1758945111.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=chris.torek@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=phillip.wood123@gmail.com \
    --cc=zara.leonardo@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.