Skip to content

Commit fc50677

Browse files
committed
libgit-rs: add get_ulong() and get_pathname() methods
Expand the ConfigSet API with additional configuration value types: - 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 <[email protected]>
1 parent 658c0e6 commit fc50677

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

contrib/libgit-rs/src/config.rs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::ffi::{c_void, CStr, CString};
2-
use std::path::Path;
2+
use std::path::{Path, PathBuf};
33

44
#[cfg(has_std__ffi__c_char)]
5-
use std::ffi::{c_char, c_int};
5+
use std::ffi::{c_char, c_int, c_ulong};
66

77
#[cfg(not(has_std__ffi__c_char))]
88
#[allow(non_camel_case_types)]
@@ -12,6 +12,10 @@ type c_char = i8;
1212
#[allow(non_camel_case_types)]
1313
type c_int = i32;
1414

15+
#[cfg(not(has_std__ffi__c_char))]
16+
#[allow(non_camel_case_types)]
17+
type c_ulong = u64;
18+
1519
use libgit_sys::*;
1620

1721
/// A ConfigSet is an in-memory cache for config-like files such as `.gitmodules` or `.gitconfig`.
@@ -82,6 +86,41 @@ impl ConfigSet {
8286

8387
Some(val != 0)
8488
}
89+
90+
/// Load the value for the given key and attempt to parse it as an unsigned long. Dies with a fatal error
91+
/// if the value cannot be parsed. Returns None if the key is not present.
92+
pub fn get_ulong(&mut self, key: &str) -> Option<u64> {
93+
let key = CString::new(key).expect("config key should be valid CString");
94+
let mut val: c_ulong = 0;
95+
unsafe {
96+
if libgit_configset_get_ulong(self.0, key.as_ptr(), &mut val as *mut c_ulong) != 0 {
97+
return None;
98+
}
99+
}
100+
Some(val as u64)
101+
}
102+
103+
/// Load the value for the given key and attempt to parse it as a file path. Dies with a fatal error
104+
/// if the value cannot be converted to a PathBuf. Returns None if the key is not present.
105+
pub fn get_pathname(&mut self, key: &str) -> Option<PathBuf> {
106+
let key = CString::new(key).expect("config key should be valid CString");
107+
let mut val: *mut c_char = std::ptr::null_mut();
108+
unsafe {
109+
if libgit_configset_get_pathname(self.0, key.as_ptr(), &mut val as *mut *mut c_char)
110+
!= 0
111+
{
112+
return None;
113+
}
114+
let borrowed_str = CStr::from_ptr(val);
115+
let owned_str = String::from(
116+
borrowed_str
117+
.to_str()
118+
.expect("config path should be valid UTF-8"),
119+
);
120+
free(val as *mut c_void); // Free the xstrdup()ed pointer from the C side
121+
Some(PathBuf::from(owned_str))
122+
}
123+
}
85124
}
86125

87126
impl Default for ConfigSet {
@@ -128,5 +167,19 @@ mod tests {
128167
assert_eq!(cs.get_bool("test.boolHundred"), Some(true)); // "100" → true
129168
// Test missing boolean key
130169
assert_eq!(cs.get_bool("missing.boolean"), None);
170+
// Test ulong parsing
171+
assert_eq!(cs.get_ulong("test.ulongSmall"), Some(42));
172+
assert_eq!(cs.get_ulong("test.ulongBig"), Some(4294967296)); // > 32-bit int
173+
assert_eq!(cs.get_ulong("missing.ulong"), None);
174+
// Test pathname parsing
175+
assert_eq!(
176+
cs.get_pathname("test.pathRelative"),
177+
Some(PathBuf::from("./some/path"))
178+
);
179+
assert_eq!(
180+
cs.get_pathname("test.pathAbsolute"),
181+
Some(PathBuf::from("/usr/bin/git"))
182+
);
183+
assert_eq!(cs.get_pathname("missing.path"), None);
131184
}
132185
}

contrib/libgit-rs/testdata/config4

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@
77
boolZero = 0
88
boolZeroZero = 00
99
boolHundred = 100
10+
ulongSmall = 42
11+
ulongBig = 4294967296
12+
pathRelative = ./some/path
13+
pathAbsolute = /usr/bin/git

contrib/libgit-sys/src/lib.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::ffi::c_void;
22

33
#[cfg(has_std__ffi__c_char)]
4-
use std::ffi::{c_char, c_int};
4+
use std::ffi::{c_char, c_int, c_ulong};
55

66
#[cfg(not(has_std__ffi__c_char))]
77
#[allow(non_camel_case_types)]
@@ -11,6 +11,10 @@ pub type c_char = i8;
1111
#[allow(non_camel_case_types)]
1212
pub type c_int = i32;
1313

14+
#[cfg(not(has_std__ffi__c_char))]
15+
#[allow(non_camel_case_types)]
16+
pub type c_ulong = u64;
17+
1418
extern crate libz_sys;
1519

1620
#[allow(non_camel_case_types)]
@@ -49,6 +53,18 @@ extern "C" {
4953
dest: *mut c_int,
5054
) -> c_int;
5155

56+
pub fn libgit_configset_get_ulong(
57+
cs: *mut libgit_config_set,
58+
key: *const c_char,
59+
dest: *mut c_ulong,
60+
) -> c_int;
61+
62+
pub fn libgit_configset_get_pathname(
63+
cs: *mut libgit_config_set,
64+
key: *const c_char,
65+
dest: *mut *mut c_char,
66+
) -> c_int;
67+
5268
}
5369

5470
#[cfg(test)]

0 commit comments

Comments
 (0)