Skip to content

Commit bd362ea

Browse files
calvin-wan-googlesteadmon
authored andcommitted
libgit: add higher-level libgit crate
The C functions exported by libgit-sys do not provide an idiomatic Rust interface. To make it easier to use these functions via Rust, add a higher-level "libgit" crate, that wraps the lower-level configset API with an interface that is more Rust-y. This combination of $X and $X-sys crates is a common pattern for FFI in Rust, as documented in "The Cargo Book" [1]. [1] https://doc.rust-lang.org/cargo/reference/build-scripts.html#-sys-packages Co-authored-by: Josh Steadmon <[email protected]> Signed-off-by: Calvin Wan <[email protected]> Signed-off-by: Josh Steadmon <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c04ee03 commit bd362ea

File tree

11 files changed

+216
-1
lines changed

11 files changed

+216
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,4 +250,5 @@ Release/
250250
/git.VC.db
251251
*.dSYM
252252
/contrib/buildsystems/out
253+
/contrib/libgit-rs/target
253254
/contrib/libgit-sys/target

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3729,7 +3729,7 @@ clean: profile-clean coverage-clean cocciclean
37293729
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
37303730
$(MAKE) -C Documentation/ clean
37313731
$(RM) Documentation/GIT-EXCLUDED-PROGRAMS
3732-
$(RM) -r contrib/libgit-sys/target
3732+
$(RM) -r contrib/libgit-rs/target contrib/libgit-sys/target
37333733
$(RM) -r contrib/libgit-sys/partial_symbol_export.o
37343734
$(RM) -r contrib/libgit-sys/hidden_symbol_export.o
37353735
$(RM) -r contrib/libgit-sys/libgitpub.a

contrib/libgit-rs/Cargo.lock

Lines changed: 77 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contrib/libgit-rs/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "libgit"
3+
version = "0.1.0"
4+
edition = "2021"
5+
build = "build.rs"
6+
rust-version = "1.63"
7+
8+
[lib]
9+
path = "src/lib.rs"
10+
11+
[dependencies]
12+
libgit-sys = { version = "0.1.0", path = "../libgit-sys" }
13+
14+
[build-dependencies]
15+
autocfg = "1.4.0"

contrib/libgit-rs/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# libgit-rs
2+
3+
Proof-of-concept Git bindings for Rust.
4+
5+
```toml
6+
[dependencies]
7+
libgit = "0.1.0"
8+
```
9+
10+
## Rust version requirements
11+
12+
libgit-rs should support Rust versions at least as old as the version included
13+
in Debian stable (currently 1.63).

contrib/libgit-rs/build.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub fn main() {
2+
let ac = autocfg::new();
3+
ac.emit_has_path("std::ffi::c_char");
4+
}

contrib/libgit-rs/src/lib.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use std::ffi::{c_void, CStr, CString};
2+
use std::path::Path;
3+
4+
#[cfg(has_std__ffi__c_char)]
5+
use std::ffi::{c_char, c_int};
6+
7+
#[cfg(not(has_std__ffi__c_char))]
8+
#[allow(non_camel_case_types)]
9+
pub type c_char = i8;
10+
11+
#[cfg(not(has_std__ffi__c_char))]
12+
#[allow(non_camel_case_types)]
13+
pub type c_int = i32;
14+
15+
use libgit_sys::*;
16+
17+
pub struct ConfigSet(*mut libgit_config_set);
18+
impl ConfigSet {
19+
pub fn new() -> Self {
20+
unsafe { ConfigSet(libgit_configset_alloc()) }
21+
}
22+
23+
pub fn add_files(&mut self, files: &[&Path]) {
24+
for file in files {
25+
let pstr = file.to_str().expect("Invalid UTF-8");
26+
let rs = CString::new(pstr).expect("Couldn't convert to CString");
27+
unsafe {
28+
libgit_configset_add_file(self.0, rs.as_ptr());
29+
}
30+
}
31+
}
32+
33+
pub fn get_int(&mut self, key: &str) -> Option<i32> {
34+
let key = CString::new(key).expect("Couldn't convert to CString");
35+
let mut val: c_int = 0;
36+
unsafe {
37+
if libgit_configset_get_int(self.0, key.as_ptr(), &mut val as *mut c_int) != 0 {
38+
return None;
39+
}
40+
}
41+
42+
Some(val.into())
43+
}
44+
45+
pub fn get_string(&mut self, key: &str) -> Option<String> {
46+
let key = CString::new(key).expect("Couldn't convert key to CString");
47+
let mut val: *mut c_char = std::ptr::null_mut();
48+
unsafe {
49+
if libgit_configset_get_string(self.0, key.as_ptr(), &mut val as *mut *mut c_char) != 0
50+
{
51+
return None;
52+
}
53+
let borrowed_str = CStr::from_ptr(val);
54+
let owned_str =
55+
String::from(borrowed_str.to_str().expect("Couldn't convert val to str"));
56+
free(val as *mut c_void); // Free the xstrdup()ed pointer from the C side
57+
Some(owned_str)
58+
}
59+
}
60+
}
61+
62+
impl Default for ConfigSet {
63+
fn default() -> Self {
64+
Self::new()
65+
}
66+
}
67+
68+
impl Drop for ConfigSet {
69+
fn drop(&mut self) {
70+
unsafe {
71+
libgit_configset_free(self.0);
72+
}
73+
}
74+
}
75+
76+
#[cfg(test)]
77+
mod tests {
78+
use super::*;
79+
80+
#[test]
81+
fn load_configs_via_configset() {
82+
let mut cs = ConfigSet::new();
83+
cs.add_files(&[
84+
Path::new("testdata/config1"),
85+
Path::new("testdata/config2"),
86+
Path::new("testdata/config3"),
87+
]);
88+
// ConfigSet retrieves correct value
89+
assert_eq!(cs.get_int("trace2.eventTarget"), Some(1));
90+
// ConfigSet respects last config value set
91+
assert_eq!(cs.get_int("trace2.eventNesting"), Some(3));
92+
// ConfigSet returns None for missing key
93+
assert_eq!(cs.get_string("foo.bar"), None);
94+
}
95+
}

contrib/libgit-rs/testdata/config1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[trace2]
2+
eventNesting = 1

contrib/libgit-rs/testdata/config2

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[trace2]
2+
eventTarget = 1

contrib/libgit-rs/testdata/config3

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[trace2]
2+
eventNesting = 3

0 commit comments

Comments
 (0)